从Java中的字符串中有效删除特定字符(一些标点符号)?

在Java中,从String中删除给定字符的最有效方法是什么? 目前,我有这个代码:

private static String processWord(String x) { String tmp; tmp = x.toLowerCase(); tmp = tmp.replace(",", ""); tmp = tmp.replace(".", ""); tmp = tmp.replace(";", ""); tmp = tmp.replace("!", ""); tmp = tmp.replace("?", ""); tmp = tmp.replace("(", ""); tmp = tmp.replace(")", ""); tmp = tmp.replace("{", ""); tmp = tmp.replace("}", ""); tmp = tmp.replace("[", ""); tmp = tmp.replace("]", ""); tmp = tmp.replace("", ""); tmp = tmp.replace("%", ""); return tmp; } 

如果我使用某种StringBuilder,或正则表达式,或者其他东西,它会更快吗? 是的,我知道:描述它并看到,但我希望有人可以提供他们头脑的答案,因为这是一项常见的任务。

这是一个迟到的答案,只是为了好玩。

在这种情况下,我建议以速度可读性为目标。 当然,你可以超级可读,但速度太慢,就像这个超简洁版本一样:

 private static String processWord(String x) { return x.replaceAll("[][(){},.;!?<>%]", ""); } 

这很慢,因为每次调用此方法时,都会编译正则表达式。 所以你可以预编译正则表达式。

 private static final Pattern UNDESIRABLES = Pattern.compile("[][(){},.;!?<>%]"); private static String processWord(String x) { return UNDESIRABLES.matcher(x).replaceAll(""); } 

假设JVM的正则表达式引擎优化了字符类查找,这对于大多数用途来说应该足够快。 这是我个人使用的解决方案。

现在没有分析,我不知道你是否可以通过制作自己的角色(实际上是代码点)查找表做得更好:

 private static final boolean[] CHARS_TO_KEEP = new boolean[]; 

填写一次,然后迭代,生成结果字符串。 我会把代码留给你。 🙂

同样,我不会深入研究这种优化。 代码变得难以阅读。 性能是一个令人担忧的问题吗? 还要记住,现代语言是JITted,在升温后它们会表现得更好,所以使用一个好的分析器。

应该提到的一件事是,原始问题中的示例非常不具有性能,因为您正在创建一大堆临时字符串! 除非编译器优化所有这些,否则该特定解决方案将执行最差。

尽管\\p{Punct}将指定比问题更广泛的字符,但它确实允许更短的替换表达式:

 tmp = tmp.replaceAll("\\p{Punct}+", ""); 

你可以这样做:

 static String RemovePunct(String input) { char[] output = new char[input.length()]; int i = 0; for (char ch : input.toCharArray()) { if (Character.isLetterOrDigit(ch) || Character.isWhitespace(ch)) { output[i++] = ch; } } return new String(output, 0, i); } // ... String s = RemovePunct("This is (a) test string."); 

如果您发现它们对您的需求变慢,那么这可能比使用正则表达式更好。

但是,如果你有一个很长的,不同的特殊字符列表,它可能会很快乱。 在这种情况下,正则表达式更容易处理。

http://ideone.com/mS8Irl

字符串是不可变的,所以不好尝试使用它们非常动态地尝试使用StringBuilder而不是String并使用它的所有精彩方法! 它会让你做任何你想做的事情。 再加上是的,如果你有想要做的事情,找出它的正则表达式,它会更好地为你工作。

使用String#replaceAll(String regex, String replacement)作为

 tmp = tmp.replaceAll("[,.;!?(){}\\[\\]<>%]", ""); System.out.println( "f,il;t!e?r(e)d {s}t[r]ig%".replaceAll( "[,.;!?(){}\\[\\]<>%]", "")); // prints "filtered string" 

现在,您的代码将遍历tmp所有字符,并将它们与您要删除的所有可能字符进行比较,因此它将使用
number of tmp characters number or characters you want to remove x number or characters you want to remove比较的number or characters you want to remove

要优化代码,可以使用短路OR || 并做一些类似的事情

 StringBuilder sb = new StringBuilder(); for (char c : tmp.toCharArray()) { if (!(c == ',' || c == '.' || c == ';' || c == '!' || c == '?' || c == '(' || c == ')' || c == '{' || c == '}' || c == '[' || c == ']' || c == '<' || c == '>' || c == '%')) sb.append(c); } tmp = sb.toString(); 

或者像这样

 StringBuilder sb = new StringBuilder(); char[] badChars = ",.;!?(){}[]<>%".toCharArray(); outer: for (char strChar : tmp.toCharArray()) { for (char badChar : badChars) { if (badChar == strChar) continue outer;// we skip `strChar` since it is bad character } sb.append(strChar); } tmp = sb.toString(); 

这样你就可以迭代每个tmp字符,但是如果它不是%那么该字符的比较次数可以减少(因为它将是最后的比较,如果字符是.程序将在一次比较中得到他的结果)。


如果我没有弄错,这种方法与字符类 ( [...] )一起使用,所以也许这样试试吧

 Pattern p = Pattern.compile("[,.;!?(){}\\[\\]<>%]"); //store it somewhere so //you wont need to compile it again tmp = p.matcher(tmp).replaceAll(""); 

你可以这样做:

 tmp.replaceAll("\\W", ""); 

删除标点符号