正则表达式很慢,如何检查一个字符串是否只有单词字符快?

时间:2013-06-21 03:03:31

标签: java regex

我有一个函数来检查一个字符串(大多数字符串只有一个CJK字符)是否只有单词字符,并且它将被调用很多次,所以成本是不可接受的,但我不知道如何优化它,有什么建议吗?

/*\w is equivalent to the character class [\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}].
 For more details see Unicode TR-18, and bear in mind that the set of characters
 in each class can vary between Unicode releases.*/
private static final Pattern sOnlyWordChars = Pattern.compile("\\w+");

private boolean isOnlyWordChars(String s) {
    return sOnlyWordChars.matcher(s).matches();
}

当s为“3g”或“go_url”或“hao123”时,isOnlyWordChars(s)应该返回true。

4 个答案:

答案 0 :(得分:4)

private boolean isOnlyWordChars(String s) {
    char[] chars = s.toCharArray();    
    for (char c : chars) {
        if(!Character.isLetter(c)) {
            return false;
        }
    }    
    return true;
}

更好的实施

public static boolean isAlpha(String str) {
    if (str == null) {
        return false;
    }
    int sz = str.length();
    for (int i = 0; i < sz; i++) {
        if (Character.isLetter(str.charAt(i)) == false) {
            return false;
        }
    }
    return true;
}

或者如果您使用的是Apache Commons,StringUtils.isAlpha()。答案的第二个实现实际上来自源码,如果isAlpha。

<强>更新

对不起迟到的回复。我不太确定速度,虽然我在几个地方读到循环比正则表达式更快。为了确保我在ideoone中运行以下代码,结果是

5000000次迭代

使用您的代码

4.99秒(之后的运行时错误,因此对于大数据不起作用)

我的第一个代码 2.71秒

使用我的第二个代码 2.52秒

进行500000次迭代

使用您的代码

1.07秒

我的第一个代码 0.36秒

我的第二个代码 0.33秒

Here是我使用的示例代码。

N.B。可能会有小错误。您可以使用它来测试不同的场景。 根据Jan的评论,我认为这些是使用私人或公共的小事。条件检查是一个很好的观点。

答案 1 :(得分:1)

我唯一看到的是将你的模式改为:

^\\w++$

但我不是java专家

说明:

我添加了锚点(即^ $),增加了模式的性能(正则表达式引擎在第一个非单词字符处失败,直到遇到结束)。我添加了一个占有量词(即++),然后正则表达式引擎与回溯位置无关,而且速度更快。

更多信息here

答案 2 :(得分:1)

我认为主要问题是你的模式。

当我注意到我的一个测试字符串Supercalifragilisticexpalidociou5失败时,我正在处理迭代解决方案。这样做的原因是:\w+只关心是否有一个或多个单词字符。 如果您没有查看已经匹配的单词,则无关紧。

要解决此问题,请使用以下方法:

(?!\W+)(\w+)

如果发现一个或多个字符是非单词字符(例如&amp; *()!@!#$),\W+条件将锁定正则表达式。

答案 3 :(得分:1)

如果你想用正则表达式做这个,那么最有效的方法是将逻辑改为否定;即“每个字母都是一个字母”变成“没有字符是非字母”。

private static final Pattern pat = Pattern.compile("\\W");

private boolean isOnlyWordChars(String s) {
    return !pat.matcher(s).find();
}

这将最多测试一次每个角色......没有回溯。