我仔细查看了源代码,找到了导致这种行为的确切问题。
String.split()
方法在内部使用 Pattern.split()
。split 方法在返回结果数组之前会检查最后匹配的索引是否存在或者是否有实际匹配。如果最后匹配的索引是 0
,那么意味着你的模式只匹配了空字符串开头或者根本没有匹配,在这种情况下,返回的数组将是一个包含相同元素的单个元素数组。
以下是源代码:
public String[] split(CharSequence input, int limit) {
int index = 0;
boolean matchLimited = limit > 0;
ArrayList<String> matchList = new ArrayList<String>();
Matcher m = matcher(input);
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) {
String match = input.subSequence(index,
input.length()).toString();
matchList.add(match);
index = m.end();
}
}
if (index == 0)
return new String[] {input.toString()};
如果上述代码中的最后一个条件 -
index == 0
,为真,则返回带有输入字符串的单个元素数组。
现在,考虑当
index
可以是
0
的情况。
- When there is no match at all. (As already in the comment above that condition)
If the match is found at the beginning, and the length of matched string is 0
, then the value of index in the if
block (inside the while
loop) -
index = m.end();
will be 0. The only possible match string is an empty string (length = 0). Which is exactly the case here. And also there shouldn't be any further matches, else index
would be updated to a different index.
考虑你的情况:
因此,要获得您想要的行为(即仅在分隔符不在开头时拆分),可以在您的正则表达式模式中添加负向回溯:
"(?<!^)(?=[dk+-])" // You don't need to escape + and hyphen(when at the end)
这将在空字符串后跟您的字符类上拆分,但不在字符串开头之前。
考虑在正则表达式模式"a(?=[dk+-])"
上拆分字符串"ad%"
的情况。这将给您一个数组,其中第一个元素为空字符串。唯一的变化是,空字符串被替换为a
:
"ad%".split("a(?=[dk+-])"); // Prints - `[, d%]`
为什么?因为匹配字符串的长度是1
。所以第一次匹配后的索引值 - m.end()
不会是0
,而是1
,因此单个元素数组将不会被返回。