当前位置: 首页 > 面试题库 >

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

冯德宇
2023-03-14
问题内容

我正在制作基于文本的骰子滚轴。它接受“ 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

  1. 当根本没有匹配项时。(如该条件上方的注释中所述)
  2. 如果在开头找到匹配项,并且匹配的字符串的长度为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()不会是0but 1,因此不会返回单个元素数组。



 类似资料:
  • 问题内容: 每当我有一个带空格的Json字符串对象时,都会收到以下错误。 Java: 杰森: 我收到以下消息: 这没有任何问题: 我在引用错误的话吗? 编辑:阅读我自己的文章后,我注意到错误消息在字符串对象值的周围没有任何引号。因此,我将xml字符串中的“更改为\”并正常工作。任何想法如何让它不删除任何引号? 问题答案: 阅读我自己的文章时,我发现错误消息在字符串对象值的周围没有任何引号。因此,我

  • 我已经做了以下工作: 将所有非内容管理的字符串翻译打包到_;()或e()函数中 > 然而,我在页面上看到的只是翻译功能所在的空白区域。它应该默认为该文本,对吗?这就是英语。 我做错了什么?我花了很多时间研究这个。顺便说一句,我不完全确定是什么。php是关于,但删除它没有什么区别。对我来说,这似乎是函数的问题。 提前谢谢。

  • 我有一个jsp页面,其中有一个下载链接。单击该链接时,它将调用一个servlet downloadservlet,该servlet从数据库获取要下载的文件。但问题是我发送给servlet的文件的标题包含空格。乙二醇= 我现在使用jsp文件下载pdf。此处pdf已下载,但无法打开。任何人都可以建议对代码进行任何更改。 下载jsp jsp页面

  • 问题 你想清理字符串前后的空白符。 解决方案 使用 JavaScript 的正则表达式来替换空白符。 要清理字符串前后的空白符,可以使用以下代码: " padded string ".replace /^\s+|\s+$/g, "" # => 'padded string' 如果只想清理字符串前面的空白符,使用以下代码: " padded string ".replace /^\s+/g,

  • 问题内容: 我有一个Pandas Dataframe,如下所示: 我想用一个空字符串删除NaN值,使其看起来像这样: 问题答案: 这可能会有所帮助。它将用空字符串替换所有NaN。