String.split(调用
Pattern.split)的行为在Java 7和Java 8之间改变。
文献资料
Pattern.split在Java 7和Java 8的文档之间进行比较,我们观察到添加了以下子句:
如果在输入序列的开头存在一个正宽匹配,则在结果数组的开头将包含一个空的前导子字符串。开头的零宽度匹配永远不会产生这样的空前导子字符串。
与Java 7相比
String.split,Java 8中还添加了相同的子句。
参考实施
让我们比较一下
Pattern.splitJava 7和Java 8中的参考实现的代码。该代码是从greppre检索的,用于版本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及更高版本中的以下行为
为了使make
split在各个版本中的行为保持一致并与Java 8中的行为兼容:
- 如果你的正则表达式可以匹配零长度字符串,则只需
(?!A)
在正则表达式的末尾添加,然后将原始正则表达式包装在非捕获组中即可(?:...)
(如有必要)。 - 如果你的正则表达式不能匹配零长度字符串,则无需执行任何操作。
- 如果你不知道正则表达式是否可以匹配零长度字符串,请执行步骤1中的两个操作。
(?!A)
检查字符串是否不以字符串开头结尾,这意味着匹配在字符串开头为空匹配。
Java 7及更高版本中的以下行为
没有通用的解决方案可以使它
split与Java 7及更低版本向后兼容,除非替换所有实例
split以指向你自己的自定义实现。



