Java正则表达式元字符在拆分时返回额外空间
我想使用正则表达式而不是StringTokenizer拆分字符串。我正在使用String.split(regex); 正则表达式包含元字符,当我使用\[时,它在返回数组中返回额外的空间Java正则表达式元字符在拆分时返回额外空间,java,regex,java-8,metacharacters,Java,Regex,Java 8,Metacharacters,我想使用正则表达式而不是StringTokenizer拆分字符串。我正在使用String.split(regex); 正则表达式包含元字符,当我使用\[时,它在返回数组中返回额外的空间 import java.util.Scanner; public class Solution{ public static void main(String[] args) { Scanner i= new Scanner(System.in); String s= i.
import java.util.Scanner;
public class Solution{
public static void main(String[] args) {
Scanner i= new Scanner(System.in);
String s= i.nextLine();
String[] st=s.split("[!\\[,?\\._'@\\+\\]\\s\\\\]+");
System.out.println(st.length);
for(String z:st)
System.out.println(z);
}
}
当我输入input[a\m]
它将数组长度返回为3和
a m
a前面也有空格。
任何人都可以解释为什么会发生这种情况,以及我如何更正它。我不希望在生成的数组中有额外的空间。因为
[
位于字符串的开头,当拆分
删除[
,在第一个拆分步骤之后会出现两个元素:字符串开头的空字符串和字符串的其余部分。不会仅返回尾随的空元素(默认情况下,它是使用limit=0
执行的)
从一开始就删除拆分所针对的字符(使用.replaceAll(“^[!\\[,?.\+\]\\s\\\]+”
,注意模式开头的^
)。以下是一个示例代码,您可以利用:
String[] st="[a\\m]".replaceAll("^[!\\[,?._'@+\\]\\s\\\\]+", "")
.split("[!\\[,?._'@+\\]\\s\\\\]+");
System.out.println(st.length);
for(String z:st) {
System.out.println(z);
}
请参见因为
[
位于字符串的开头,所以当拆分删除[
时,在第一个拆分步骤后会出现两个元素:位于字符串开头的空字符串和字符串的其余部分。不会仅返回尾随的空元素(默认情况下,它是以limit=0
执行的)
从一开始就删除拆分所针对的字符(使用.replaceAll(“^[!\\[,?.\+\]\\s\\\]+”
,注意模式开头的^
)。以下是一个示例代码,您可以利用:
String[] st="[a\\m]".replaceAll("^[!\\[,?._'@+\\]\\s\\\\]+", "")
.split("[!\\[,?._'@+\\]\\s\\\\]+");
System.out.println(st.length);
for(String z:st) {
System.out.println(z);
}
请参见作为补充,您可以通过直接处理包来执行相同的操作,而无需指定两次模式。删除此冗余可以避免潜在错误,并且可能更有效,因为模式不需要解析两次:
Pattern p = Pattern.compile("[!\\[,?\\._'@\\+\\]\\s\\\\]+");
Matcher m = p.matcher(s);
if(m.lookingAt()) s=m.replaceFirst("");
String[] st = p.split(s);
for(String z:st)
System.out.println(z);
为了能够使用相同的模式,即不必使用锚点^
来移除前导分隔符,我们首先通过lookingAt()进行检查
在删除第一个匹配项之前,该模式是否在文本开头真正匹配。然后,我们继续执行拆分
操作,但重用已经准备好的模式
关于注释中提到的问题,split
操作将始终返回至少一个元素,即不匹配的输入字符串,即使该字符串为空。如果希望使用空数组,唯一的解决方案是显式替换结果:
if(st.length==1 && s.equals[0]) st=new String[0];
或者,如果您只想特别处理空字符串,您可以事先检查:
if(s.isEmpty()) st=new String[0];
else {
// the code as shown above
}
除此之外,您还可以通过直接处理包来执行相同的操作,而无需指定两次模式。删除此冗余可以避免潜在错误,并且可能更有效,因为模式不需要解析两次:
Pattern p = Pattern.compile("[!\\[,?\\._'@\\+\\]\\s\\\\]+");
Matcher m = p.matcher(s);
if(m.lookingAt()) s=m.replaceFirst("");
String[] st = p.split(s);
for(String z:st)
System.out.println(z);
为了能够使用相同的模式,即不必使用锚点^
来移除前导分隔符,我们首先通过lookingAt()进行检查
在删除第一个匹配项之前,该模式是否在文本开头真正匹配。然后,我们继续执行拆分
操作,但重用已经准备好的模式
对于注释中提到的问题,即使字符串为空,也会始终返回至少一个元素,即输入字符串,当没有匹配时,即使字符串为空。如果希望有空数组,唯一的解决方案是显式替换结果:
if(st.length==1 && s.equals[0]) st=new String[0];
或者,如果您只想特别处理空字符串,您可以事先检查:
if(s.isEmpty()) st=new String[0];
else {
// the code as shown above
}
你的意思是要有一个输入字符串string s=“[a\\m]”
?因为你匹配了[
和]
:你只是得到一个空字符串作为数组中的第一个元素,因为你的输入是从[
开始的,而拆分是在上完成的[
也一样。从开头删除所有这些字符。不,它不会删除所有字符,只删除开头的字符。您对这些前导符号不感兴趣,因为它们生成空数组元素,对吗?因此,仅在字符串开头删除它们是一种有效的方法。您的意思是要有一个输入字符串字符串s=“[a\\m]”
?因为您匹配了[
和]
:您只得到一个空字符串作为数组中的第一个元素,因为您的输入从[
开始,并且拆分是在上完成的[
也是。从开头删除所有这些字符。不,它不会删除所有字符,只删除开头的字符。您对这些前导符号不感兴趣,因为它们生成空数组元素,对吗?因此,仅在字符串开头删除它们是一种有效的方法。非常感谢您的详细解释和代码:)先生,如果我只输入!或[它仍然返回1,而它应该返回0:(这是因为当您拆分一个空字符串时,您将得到一个空元素。用于处理这种情况。由于Java 6,您可以使用string.isEmpty()
而不是string.length()!=0
,但这只是风格上的不同…我使用“\\\”而不是“”,现在替换时它返回0感谢您的详细解释和代码:)先生,如果我只输入!或者[它仍然返回1,而它应该返回0:(这是因为当拆分空字符串时,您将得到1个空元素。用于处理这种情况。由于Java 6,您可以使用string.isEmpty()
而不是string.length()!=0
,但这只是风格上的不同…我使用“\\\\\”而不是“”,替换时现在返回0