Psh*_*emo 107 java regex split java-8
在Java 8之前我们拆分空字符串之类的
String[] tokens = "abc".split("");
Run Code Online (Sandbox Code Playgroud)
分裂机制会在标有的地方分开 |
|a|b|c|
Run Code Online (Sandbox Code Playgroud)
因为""
每个字符前后都有空格.因此,它最初将生成此数组
["", "a", "b", "c", ""]
Run Code Online (Sandbox Code Playgroud)
然后将删除尾随的空字符串(因为我们没有明确地为limit
参数提供负值),所以它最终会返回
["", "a", "b", "c"]
Run Code Online (Sandbox Code Playgroud)
在Java 8中,拆分机制似乎已经发生了变化.现在我们用的时候
"abc".split("")
Run Code Online (Sandbox Code Playgroud)
我们将得到["a", "b", "c"]
数组,而不是["", "a", "b", "c"]
看起来像开始时的空字符串也被删除.但是这个理论失败了,例如
"abc".split("a")
Run Code Online (Sandbox Code Playgroud)
在start时返回带有空字符串的数组["", "bc"]
.
有人可以解释这里发生了什么,以及这些案例的拆分规则在Java 8中是如何变化的?
nha*_*tdh 83
Java 7和Java 8之间String.split
(调用Pattern.split
)的行为发生了变化.
的文档之间的比较Pattern.split
中的Java 7和Java的8,我们遵守以下条款添加:
当在输入序列的开头存在正宽度匹配时,在结果数组的开头包括空的前导子串.然而,开头的零宽度匹配从不会产生这样的空前导子串.
与Java 7相比String.split
,Java 8中还添加了相同的子句.
让我们比较Pattern.split
Java 7和Java 8中的参考实现的代码.从grepcode中检索代码,版本为7u40-b43和8-b132.
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);
}
Run Code Online (Sandbox Code Playgroud)
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);
}
Run Code Online (Sandbox Code Playgroud)
在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;
}
Run Code Online (Sandbox Code Playgroud)
要使split
各个版本的行为保持一致并与Java 8中的行为兼容:
(?!\A)
在正则表达式的末尾添加并将原始正则表达式包装在非捕获组中(?:...)
(如果需要).(?!\A)
检查字符串是否不在字符串的开头结束,这意味着匹配是字符串开头的空匹配.
没有通用的解决方案可以split
向后兼容Java 7和之前的版本,split
只需将所有实例替换为指向您自己的自定义实现.
Ale*_* C. 30
这已在文档中指定split(String regex, limit)
.
当在该字符串的开头存在正宽度匹配时,在结果数组的开头包含空的前导子字符串.然而,开头的零宽度匹配从不会产生这样的空前导子串.
在"abc".split("")
开头有一个零宽度匹配,因此前导空子字符串不包含在结果数组中.
但是,在拆分时,在第二个片段中,"a"
您获得了正宽度匹配(在本例中为1),因此按预期包含空的前导子字符串.
(删除了不相关的源代码)
ars*_*jii 14
split()
从Java 7到Java 8 的文档略有变化.具体来说,添加了以下语句:
当在该字符串的开头存在正宽度匹配时,在结果数组的开头包含空的前导子字符串.然而,开头的零宽度匹配从不会产生这样的空前导子串.
(强调我的)
空字符串拆分在开头生成零宽度匹配,因此根据上面指定的内容,在结果数组的开头不包括空字符串.相比之下,分裂的第二个示例在字符串的开头"a"
生成正宽度匹配,因此实际上在结果数组的开头包含空字符串.