3

我有一个函数来检查一个字符串(大部分字符串只有一个 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

4 回答 4

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()。答案的第二个实现实际上来自源代码 if isAlpha。

更新

嗨 抱歉回复晚了。尽管我在几个地方读到循环比正则表达式快,但我不太确定速度。为了确保我在ideoone中运行以下代码,结果如下

5000000 次迭代

使用您的代码: 4.99 秒(之后出现运行时错误,因此对于大数据它不起作用)

我的第一个代码 2.71 秒

用我的第二个代码 2.52 秒

500000 次迭代

使用您的代码: 1.07 秒

用我的第一个代码 0.36 秒

用我的第二个代码 0.33 秒

是我使用的示例代码。

注意可能会有小错误。您可以使用它在不同的场景中进行测试。根据 Jan 的评论,我认为这些都是小事,比如使用私人或公共。最好的条件检查是一个很好的观点。

于 2013-06-21T03:10:17.723 回答
1

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

^\\w++$

但我不是java专家

解释:

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

更多信息在这里

于 2013-06-21T03:09:40.673 回答
1

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

当我注意到它在我的一个测试字符串上失败时,我正在研究一个迭代解决方案Supercalifragilisticexpalidociou5。这个原因是: \w+只关心是否有一个或多个单词字符。 它并不关心您是否正在查看已经匹配的单词字符。

要纠正此问题,请使用环视:

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

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

于 2013-06-21T03:29:37.517 回答
1

如果您想使用正则表达式执行此操作,那么最有效的方法是将逻辑更改为否定;即“每个字符都是一个字母”变成“没有一个字符是非字母”。

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

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

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

于 2013-06-21T05:35:40.613 回答