Java String.split()有时会给出空白字符串
我正在制作基于文本的骰子滚轴。它接受“ 2d10 +
5”之类的字符串,并作为滚动结果返回一个字符串。我的问题出现在令牌生成器中,该令牌生成器将字符串拆分为有用的部分,以便我解析为信息。
String[] tokens = message.split("(?=[dk\\+\\-])");
这会产生奇怪的意外结果。我不知道是什么原因造成的。可能是正则表达式,我的误解,或者Java只是Java。这是正在发生的事情:
3d6+4
产生字符串数组[3, d6, +4]
。这是对的。d%
产生字符串数组[d%]
。这是对的。d20
产生字符串数组[d20]
。这是对的。d%+3
产生字符串数组[, d%, +3]
。这是不正确的。d20+2
产生字符串数组[, d20, +2]
。这是不正确的。
在第四和第五个示例中,一些奇怪的事情导致一个多余的空字符串出现在数组的前面。这不是字符串开头缺少数字的原因,其他示例也证明了这一点。它不是百分号,也不是加号。
现在,我只是继续在空白字符串上进行for循环,但这有点像创可贴解决方案。有谁知道导致数组开头空白字符串的原因?我该如何解决?
回答:
深入研究源代码,我发现了此行为背后的确切问题。
该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);
// 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);
// Consider this assignment. For a single empty string match
// m.end() will be 0, and hence index will also be 0
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()};
// Rest of them is not required
如果以上代码中的最后一个条件- index == 0
为true,则返回包含输入字符串的单个元素数组。
现在,考虑index
可以为的情况0
。
- 当根本没有匹配项时。(如该条件上方的注释中所述)
- 如果在开头找到匹配项,并且匹配的字符串的长度为
0
,则该if
块中(while
循环内)的index值-index = m.end();
将为0。唯一可能的匹配字符串是一个 空字符串 (长度= 0)。这就是这里的情况。并且也不应再有其他匹配项,否则index
将更新为其他索引。
因此,请考虑您的情况:
对于
d%
,在第一个模式之前只有一个匹配项d
。因此,索引值为0
。但是由于没有其他匹配项,索引值不会更新,if
条件变为true
,并返回具有原始字符串的单个元素数组。因为
d20+2
将有两场比赛,一场比赛之前d
,一场比赛之前+
。因此索引值将被更新,因此ArrayList
将返回上述代码中的,其中包含空字符串,这是由于分隔符分割而导致的,该分隔符是字符串的第一个字符,如@Stema的答案中所述。
因此,要获得所需的行为(仅当分隔符不在开头时才在分隔符上拆分,可以在正则表达式模式中添加负向后看):
"(?<!^)(?=[dk+-])" // You don't need to escape + and hyphen(when at the end)
这将拆分为空字符串,后跟您的字符类,但不以字符串开头。
考虑"ad%"
在正则表达式模式-
上拆分字符串的情况"a(?=[dk+-])"
。这将为您提供一个数组,其中第一个元素为空字符串。唯一的变化是,空字符串替换为a
:
"ad%".split("a(?=[dk+-])"); // Prints - `[, d%]`
为什么?这是因为匹配的字符串的长度为1
。因此,第一个匹配项之后的索引值- m.end()
不会是0
but 1
,因此不会返回单个元素数组。
以上是 Java String.split()有时会给出空白字符串 的全部内容, 来源链接: utcz.com/qa/427654.html