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

Sup*_*Cow 0 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]);
Run Code Online (Sandbox Code Playgroud)

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

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

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

谢谢您的帮助!

Bor*_*der 6

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

  • 没有
  • 882
  • 337
  • 没有

但是,正如你调用String.split(delimiter),这就要求String.split(delimiter, limit)有一个limit零.

文档:

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

(强调我的)

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


通常情况下,来标记这样的事情,一会去的组合replaceAllsplit:

final String[] tokens = input.replaceAll("^\\[|\\]$").split(",");
Run Code Online (Sandbox Code Playgroud)

这将首先剥离start(^[)和end(]$)括号,然后拆分,.这样,您就不必拥有一些有点钝的程序逻辑,您可以从任意索引开始循环.


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

首先,我们需要在Regex中定义我们想要的标记(而不是我们要分割的标记) - 在这种情况下它很简单,它只是数字\d.

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

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
}
Run Code Online (Sandbox Code Playgroud)

注意:我使用占有式正则表达式来提高效率

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