为什么在Java String.split(regex)中有空标记?

为什么在Java String.split(regex)中有空标记?,java,regex,Java,Regex,我不熟悉正则表达式,我试图用它来解析由“(“,”)和空格分隔的标记。这是我的尝试: String str = "(test (_bit1 _bit2 |bit3::&92;test#4|))"; String[] tokens = str.split("[\\s*[()]]"); for(int i = 0; i < tokens.length; i++) System.out.println(i + " : " + tokens[i]); String str=“(测试(

我不熟悉正则表达式,我试图用它来解析由“(“,”)和空格分隔的标记。这是我的尝试:

String str = "(test (_bit1 _bit2 |bit3::&92;test#4|))";
String[] tokens = str.split("[\\s*[()]]"); 
for(int i = 0; i < tokens.length; i++)
  System.out.println(i + " : " + tokens[i]);
String str=“(测试(_bit1 | u bit2 | bit3::&92;测试#4 |”)”;
字符串[]标记=str.split(“[\\s*[()]”);
for(int i=0;i
我期望得到以下结果:

0:测试
1:_bit1
2:_bit2
3:|比特3::&92;测试#4|

但是,实际输出中会出现两个空标记:

0:
1:测试
2:
3:_bit1
4:_bit2
5:|比特3::&92;测试#4 |

我不明白为什么我在位置0和2有两个空令牌。谁能给我一个提示吗?多谢各位

====更新====

答案是谁删除了它。但是我喜欢这个答案,所以我把它复制到这里作为我自己的参考

您的正则表达式[\s*[()]]与一个空格字符(\s)或其中一个匹配 字符*、(、或)。字段开头的分隔符 string(()是您获得第一个空令牌的原因。没有办法 您只需检查第一个令牌是否为空,然后忽略它

第二个空令牌位于第一个空格和 跟它走。那个在你身上,因为你用了*(零或更多) 而不是+(一个或多个)。但是修复它并不是那么简单。你想要 在空格、paren或两者上拆分,但必须确保 至少有一个字符,以其中一个为准。这可能会:

\s*[()]+\s*|\s+

但您可能也应该考虑到paren之间的空格:

\s*(?:[()]+\s*)+\s+

作为Java字符串文字,这将是:

\s*(?:[()]+\s*)+\s+


您的regexp错误,请尝试以下操作:

字符串[]标记=str.split([\s(\)]+”

更新:我注意到你的代码实际上删除了括号,所以看起来你不必在括号中转义它们…不知道为什么,任何人都可以回答这个问题


新更新:感谢@Alanmore的解释,据我所知,
[]
中的括号不需要转义。

您的regexp错误,请尝试以下操作:

字符串[]标记=str.split([\s(\)]+”

更新:我注意到你的代码实际上删除了括号,所以看起来你不必在括号中转义它们…不知道为什么,任何人都可以回答这个问题


新更新:感谢@Alanmore的解释,据我所知,
[]
中的括号不需要转义。

索引0是第一个
)之前的标记。索引2是输入字符串中空格和第二个
)之间的标记

我不认为你可以避免第一个,但你可以通过使用

str.split("[\\s()]+");

索引0是第一个
)之前的标记。索引2是输入字符串中空格和第二个
)之间的标记

我不认为你可以避免第一个,但你可以通过使用

str.split("[\\s()]+");

我的建议是,首先从两端删除拆分字符(以避免空字符串),然后进行拆分

String[] tokens = str.replaceAll("^[\\s()]+|[\\s()]+$", "").split("[\\s()]+"); 
                           -- replace leading or trailing--

此外,我已将拆分字符(空格,
)放在字符类
[]

中。我的建议是,首先从两端删除拆分字符(以避免空字符串),然后进行拆分

String[] tokens = str.replaceAll("^[\\s()]+|[\\s()]+$", "").split("[\\s()]+"); 
                           -- replace leading or trailing--

此外,我还将拆分字符(空格,
)放在字符类
[]

中。您遇到的问题是,它在分隔符之间创建一个空字符串,然后在碰到分隔符时返回它

通过添加一个额外的(例如:

String str = "(test (_bit1 (_bit2 |bit3::&92;test#4|))";
然后,输出将变为:

0 : 
1 : test
2 : 
3 : _bit1
4 : 
5 : _bit2
6 : |bit3::&92;test#4|
我建议使用以下代码:

String str = "(test (_bit1 (_bit2 |bit3::&92;test#4|))";
String[] tokensArray = str.split("[\\s[()]*]");
ArrayList<String> tokens = new ArrayList<>();
for (String token : tokensArray) {
    if (!token.isEmpty()) {
        tokens.add(token);
    }
}
for (int i = 0; i < tokens.size(); i++)
    System.out.println(i + " : " + tokens.get(i));
String str=“(test(_bit1(_bit2 | bit3::&92;test#4 |”)”;
字符串[]tokensArray=str.split(“[\\s[()]*]”);
ArrayList标记=新的ArrayList();
for(字符串标记:tokensArray){
如果(!token.isEmpty()){
令牌。添加(令牌);
}
}
for(inti=0;i

这样做的目的是从数组中删除任何空标记,因为这些标记被认为是“不正确的”标记。

您遇到的问题是,它在分隔符之间创建一个空字符串,然后在碰到分隔符时返回它

通过添加一个额外的(例如:

String str = "(test (_bit1 (_bit2 |bit3::&92;test#4|))";
然后,输出将变为:

0 : 
1 : test
2 : 
3 : _bit1
4 : 
5 : _bit2
6 : |bit3::&92;test#4|
我建议使用以下代码:

String str = "(test (_bit1 (_bit2 |bit3::&92;test#4|))";
String[] tokensArray = str.split("[\\s[()]*]");
ArrayList<String> tokens = new ArrayList<>();
for (String token : tokensArray) {
    if (!token.isEmpty()) {
        tokens.add(token);
    }
}
for (int i = 0; i < tokens.size(); i++)
    System.out.println(i + " : " + tokens.get(i));
String str=“(test(_bit1(_bit2 | bit3::&92;test#4 |”)”;
字符串[]tokensArray=str.split(“[\\s[()]*]”);
ArrayList标记=新的ArrayList();
for(字符串标记:tokensArray){
如果(!token.isEmpty()){
令牌。添加(令牌);
}
}
for(inti=0;i

这样做的目的是从数组中删除任何空标记,因为这些标记被认为是“不正确的”令牌。

谢谢,但它不起作用。此正则表达式将字符串拆分为字符。您希望使用
+
,而不是
*
。您的正则表达式将在任何应用位置匹配,因为它不必使用任何字符。谢谢,但它不起作用。此正则表达式将字符串拆分为字符。您想使用
+
,而不是
*
。正则表达式无论在哪里应用都会匹配,因为它不需要使用任何字符。括号在字符类中时不需要转义。内部的方括号集并不重要。Java(并且只有Java)将其视为“嵌套的”字符类,它与其他东西联合在一起,所以它就像
[\s*()]
。解决方案是去掉括号内的
*
,在括号外添加一个
+
,如