使用具有多个分隔符的拆分感到困惑

时间:2016-01-28 23:28:40

标签: java split

我练习阅读输入然后对其进行标记。 例如,如果我有[882,337]我想得到数字882和337.我尝试使用以下代码:

    String test = "[882,337]";
    String[] tokens = test.split("\\[|\\]|,");
    System.out.println(tokens[0]);
    System.out.println(tokens[1]);
    System.out.println(tokens[2]);

它有点工作,输出是: (空行) 882 337

我不明白为什么令牌[0]为空?我希望只有两个令牌,其中令牌[0] = 882,令牌[1] = 337.

我检查了一些链接,但没有找到答案。

感谢您的帮助!

4 个答案:

答案 0 :(得分:6)

拆分拆分给定的String。如果你split" [882,337]"在" ["或","或"]"那你实际上有:

  • 没有
  • 882
  • 337
  • 没有

但是,正如您调用了String.split(delimiter),这会调用String.split(delimiter, limit)limit为零。

来自documentation

  

limit参数控制模式的应用次数,因此会影响结果数组的长度。如果限制n大于零,那么该模式最多会应用n - 1次,数组的长度不会超过n,并且数组的数量不会超过n ;最后一个条目将包含除最后一个匹配分隔符之外的所有输入。如果n是非正数,则模式将被应用尽可能多次,并且数组可以具有任何长度。 如果replaceAll为零,则模式将被应用尽可能多次,数组可以具有任意长度,并且尾随空字符串将被丢弃。

(强调我的)

因此,在此配置中,最后的空字符串将被丢弃。因此,您将完全拥有所拥有的东西。

通常,为了对这样的内容进行标记,可以选择splitfinal String[] tokens = input.replaceAll("^\\[|\\]$").split(","); 的组合:

^[

这将首先剥离开头(]$)和结束(,)括号,然后在Pattern上拆分。这样你就不必有一些有点钝的程序逻辑,你可以从任意索引开始循环。

作为替代方案,对于更复杂的标记化,可以使用replaceAll - 这里可能有些过分,但在编写多个\d链之前,请记住这一点。

首先,我们需要在Regex中定义我们想要的令牌(而不是我们要拆分的令牌) - 在这种情况下它很简单,它只是数字所以{{1 }}

因此,为了从任意String on中提取所有数字(无数千/小数分隔符)值,将执行以下操作:

final List<Integer> tokens = new ArrayList<>();    <-- to hold the tokens
final Pattern pattern = Pattern.compile("\\d++");  <-- the compiled regex
final Matcher matcher = pattern.matcher(input);    <-- the matcher on input

while(matcher.find()) {                            <-- for each matched token
    tokens.add(Integer.parseInt(matcher.group())); <-- parse and `int` and store
}

N.B:我使用占有正则表达式来提高效率

所以,你看,上面的代码比简单的replaceAll().split()稍微复杂一些,但它更具可扩展性。您可以使用任意复杂的正则表达式来标记almost any输入。

答案 1 :(得分:3)

分割字符串的符号在这里:

String test = "[882,337]";
               ^   ^   ^

因为第一个字符与您的分隔符匹配,所以从它开始的所有内容都将是第一个结果。好吧,从第一个字母开始就没有了,所以结果是空字符串。

由于最后一个符号也与分隔符匹配,因此可以预期结束时会出现相同的行为。的

  

因此,结尾的空字符串不包含在结果数组中。

请参阅Javadoc

答案 2 :(得分:2)

那是因为每个分隔符都有&#34;之前&#34; &#34;&#34;&#34;&#34;结果,即使它是空的。考虑

  

882337

您希望产生两个结果。 同样,你期望

  

882337,

生成三个,最后一个为空(假设你的限制足够大,或者假设你几乎使用split()的任何其他语言/实现)。从逻辑上扩展,

  

,882337,

必须产生四个,第一个和最后一个结果为空。这是你的情况,除了你有多个分隔符。

答案 3 :(得分:2)

分裂从一件事中创造出两件(或更多件)的东西。例如,如果您按a,b分割,,则会获得ab

但是如果是",b",您将获得"""b"。你可以这样想: ""存在于字符串的所有字符的开头,结尾甚至中间:

""+","+"b" - &gt; ",b"因此,如果我们对此","进行拆分,我们会左右两部分:"""b"

类似的情况发生在"a,"的情况下,并且第一个结果数组是["a",""]但是这里split方法删除尾随空字符串并仅返回["a"](您可以关闭这种清算机制使用split(",", -1))。

所以

String test = "[882,337]";
String[] tokens = test.split("\\[|\\]|,");
你正在分裂:

     ""+"["+"882"+","+"337"+"]"+""
here:    ^         ^         ^

首先创建数组["", "882", "337", ""],然后删除尾随空字符串,最后你收到:

["", "882", "337"]

仅从结果数组的开头删除空字符串的情况是

  • 您正在使用Java 8(或更新版本)并在正则表达式上进行拆分,其长度为split(""),或者在每个x之前使用split("(?=x)")说明(更多信息请参阅:{{ 3}})
  • 当这个空字符串是split方法的结果时。例如"".split("") 不会删除 "",更多信息请点击此处:Why in Java 8 split sometimes removes empty strings at start of result array?