2013-06-21 14 views
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。

+0

你認爲空字符串有效嗎? (即w *而不是w +) – SK9

+0

可能的重複[最快的方法來檢查字符串是否只包含數字](http://stackoverflow.com/questions/7461080/fastest-way-to-check-if-string-contains-只有數字) – SK9

+0

@ SK9 c#和java是不同的語言:P – nachokk

回答

1

我看到的唯一的事情就是你的模式更改爲:

^\\w++$ 

但我不是一個Java專家

解釋:

我已經加入錨(即^$ ),這增加了模式的表現(正則表達式引擎在第一個非單詞字符失敗,直到遇到結束)。我添加了一個佔有量詞(即++),那麼正則表達式引擎並不關心回溯位置,而且速度更快。

更多信息here

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下議院,StringUtils.isAlpha()。答案的第二個實現實際上來自源代碼,如果isAlpha。

UPDATE

HI很抱歉這麼晚纔回復。雖然我在幾個地方看到循環比正則表達式快,但我對速度並不確定。爲了確保我在ideoone運行下面的代碼,這裏是結果

爲5000000迭代

與代碼:4.99秒(運行時錯誤之後,這麼大數據它不工作)

與我的第一代碼2.71秒

與我的第二代碼2.52秒

爲500000迭代

與代碼:1.07秒

我的第一個代碼0.36秒

我的第二個代碼0.33秒

Here爲樣本我使用的代碼。

N.B.可能會有小錯誤。你可以玩它來測試不同的場景。 根據Jan的評論,我認爲這些是使用私人或公共的小事。最好的條件檢查是一個很好的觀點。

+4

multiple return和== false是更好的實現嗎? – nachokk

+1

@nachokk取決於你的常見情況;第一個「if」甚至不會被編譯。 –

+0

我更新了我的問題,「\ w相當於角色分類[\ p {Ll} \ p {Lu} \ p {Lt} \ p {Lo} \ p {Nd}]。」例如當字符串是「3g」或「go_url」或「hao123」時,isOnlyWordChars(s)應該返回true。 – iclinux

1

我認爲主要問題是你的模式。

我正在通過迭代解決方案,當我發現它在我的測試字符串Supercalifragilisticexpalidociou5之一上失敗時。原因如下:\w+只關心是否有一個或多個單詞字符。 它並不關心你是否看不到它已經匹配的單詞字符

爲了改善這種情況,使用環視:

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

\W+條件將鎖定正則表達式,如果一個或多個字符被認爲是一個非單詞字符(如& *()@! #$)。

+0

這種向前看將永遠不會過濾任何東西。非字詞序列從來沒有開始於字詞序列。也許你希望lookahead是'(?!\ w * \ W +)'並且還要添加字符串錨? –

+0

解釋正確,但整改不足。 –

+0

是的,我測試這個,它不比我的快... – iclinux

1

如果你想使用正則表達式來做到這一點,那麼最有效的方法是將邏輯改爲否定;即「每個字符是一個字母」變成「沒有字符是一個非字母」。

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

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

這將測試每個角色最多一次...沒有回溯。

+0

謝謝,但它不適用於我的情況,因爲在我的情況下,幾乎所有的「s」只有一個cjk字符...老方法成本[61032] ns,您的平均成本[58115] ns。 – iclinux

+0

是否有一種方法來檢查一個字符是「\ w」而沒有regx?因爲大部分字符串都是長度爲1. – iclinux

+0

是的,當然有。像StinePike的答案一樣使用循環。 –

相關問題