Поведінка 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("(?!^)")
здається, працює.