gpt4 book ai didi

Java String.split() 有时会给出空白字符串

转载 作者:搜寻专家 更新时间:2023-10-30 19:56:44 24 4
gpt4 key购买 nike

我正在制作基于文本的掷骰子。它接受像“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 为真,则单个元素数组与输入字符串一起返回。

现在,考虑 index 可以是 0 的情况。

  1. 当根本没有匹配项时。 (正如该条件上方的评论中所述)
  2. 如果在开头找到匹配,且匹配到的字符串长度为0,则if block 中index的值(在while 循环) -

    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)

这将拆分为空字符串,后跟您的字符类,但前面没有字符串的开头。


考虑在正则表达式模式 - "a(?=[dk+-])" 上拆分字符串 "ad%" 的情况。这将为您提供一个第一个元素为空字符串的数组。这里唯一的变化是,空字符串被替换为 a:

"ad%".split("a(?=[dk+-])");  // Prints - `[, d%]`

为什么?那是因为匹配字符串的长度是1。所以第一次匹配后的索引值 - m.end() 不会是 0 而是 1,因此单元素数组获胜'被退回。

关于Java String.split() 有时会给出空白字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18870699/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com