Поведінка String.split(що викликає Pattern.split) змінюється між Java 7 та Java 8.
Документація
Порівнюючи документацію Pattern.splitв Java 7 та Java 8 , ми спостерігаємо додане наступне застереження:
Якщо на початку вхідної послідовності є відповідність позитивної ширини, то на початку результуючого масиву додається порожній провідний підряд. Зрівняння нульової ширини на початку, однак ніколи не створює такої порожньої провідної підрядки.
Ж розділ також додається String.splitв Java 8 , по порівнянні з Java 7 .
Довідкова реалізація
Порівняємо код Pattern.splitпосилальної реалізації на Java 7 та Java 8. Код отриманий із grepcode для версій 7u40-b43 та 8-b132.
Java 7
public String[] split(CharSequence input, int limit) {
int index = 0;
boolean matchLimited = limit > 0;
ArrayList<String> matchList = new ArrayList<>();
Matcher m = matcher(input);
// Add segments before each match found
while(m.find()) {
if (!matchLimited || matchList.size() < limit - 1) {
String match = input.subSequence(index, m.start()).toString();
matchList.add(match);
index = m.end();
} else if (matchList.size() == limit - 1) { // last one
String match = input.subSequence(index,
input.length()).toString();
matchList.add(match);
index = m.end();
}
}
// If no match was found, return this
if (index == 0)
return new String[] {input.toString()};
// Add remaining segment
if (!matchLimited || matchList.size() < limit)
matchList.add(input.subSequence(index, input.length()).toString());
// Construct result
int resultSize = matchList.size();
if (limit == 0)
while (resultSize > 0 && matchList.get(resultSize-1).equals(""))
resultSize--;
String[] result = new String[resultSize];
return matchList.subList(0, resultSize).toArray(result);
}
Java 8
public String[] split(CharSequence input, int limit) {
int index = 0;
boolean matchLimited = limit > 0;
ArrayList<String> matchList = new ArrayList<>();
Matcher m = matcher(input);
// Add segments before each match found
while(m.find()) {
if (!matchLimited || matchList.size() < limit - 1) {
if (index == 0 && index == m.start() && m.start() == m.end()) {
// no empty leading substring included for zero-width match
// at the beginning of the input char sequence.
continue;
}
String match = input.subSequence(index, m.start()).toString();
matchList.add(match);
index = m.end();
} else if (matchList.size() == limit - 1) { // last one
String match = input.subSequence(index,
input.length()).toString();
matchList.add(match);
index = m.end();
}
}
// If no match was found, return this
if (index == 0)
return new String[] {input.toString()};
// Add remaining segment
if (!matchLimited || matchList.size() < limit)
matchList.add(input.subSequence(index, input.length()).toString());
// Construct result
int resultSize = matchList.size();
if (limit == 0)
while (resultSize > 0 && matchList.get(resultSize-1).equals(""))
resultSize--;
String[] result = new String[resultSize];
return matchList.subList(0, resultSize).toArray(result);
}
Додавання наступного коду в Java 8 виключає збіг нульової довжини на початку вхідного рядка, що пояснює поведінку вище.
if (index == 0 && index == m.start() && m.start() == m.end()) {
// no empty leading substring included for zero-width match
// at the beginning of the input char sequence.
continue;
}
Підтримання сумісності
Слідкуйте за поведінкою в Java 8 і вище
Щоб зробити splitповедінку послідовно в різних версіях та сумісною з поведінкою в Java 8:
- Якщо ваш регекс може відповідати рядку нульової довжини, просто додайте
(?!\A)в кінці регулярного вираження і загортайте оригінальний регулярний вираз у групу, яка не захоплює (?:...)(якщо потрібно).
- Якщо ваш регулярний вираз не може відповідати рядку нульової довжини, вам нічого не потрібно робити.
- Якщо ви не знаєте, чи може регулярний вираз відповідати рядку нульової довжини чи ні, виконайте обидві дії на кроці 1.
(?!\A) перевіряє, що рядок не закінчується на початку рядка, що означає, що збіг є порожнім збігом на початку рядка.
Слідкуючи за поведінкою в Java 7 і раніше
Немає загального рішення зробити splitзворотну сумісність з Java 7 та попередньою, не замінивши всіх примірників, splitщоб вказати на власну власну реалізацію.
s.split("(?!^)")здається, працює.