2012-03-01 1 views
32

言いますマッチしたRegexでこれをどのように達成できますか?Java Regexを使用して、文字列にセット内の単語が含まれているかどうかをチェックする方法は?私は文が上記のいずれかのワードが含まれているかどうかを確認したい</p> <p>リンゴ、オレンジ、梨、バナナ、キウイ、そしてそれがない場合は、私は言葉を見つけたい - 私は単語のセットを持って

私は現在、自分の言葉のセットごとにString.indexOf()を呼び出しています。私はこれが正規表現のマッチングほど効率的ではないと仮定していますか?

答えて

47

TL; DRを簡単なストリングについては、最善のが、ためです一致する全単語だけ正規表現がおそらく良いです。

どの方法が効率的かを確認する最も良い方法は、テストすることです。

String.indexOf()の代わりにString.contains()を使用すると、正規表現以外のコードを簡略化できます。

は、正規表現は、このようになります別の単語を検索するには、次の正規表現で ORとして

apple|orange|pear|banana|kiwi 

|作品。

私の非常に簡単なテストコードは次のようになります。

public class TestContains { 

    private static String containsWord(Set<String> words,String sentence) { 
    for (String word : words) { 
     if (sentence.contains(word)) { 
     return word; 
     } 
    } 

    return null; 
    } 

    private static String matchesPattern(Pattern p,String sentence) { 
    Matcher m = p.matcher(sentence); 

    if (m.find()) { 
     return m.group(); 
    } 

    return null; 
    } 

    public static void main(String[] args) { 
    Set<String> words = new HashSet<String>(); 
    words.add("apple"); 
    words.add("orange"); 
    words.add("pear"); 
    words.add("banana"); 
    words.add("kiwi"); 

    Pattern p = Pattern.compile("apple|orange|pear|banana|kiwi"); 

    String noMatch = "The quick brown fox jumps over the lazy dog."; 
    String startMatch = "An apple is nice"; 
    String endMatch = "This is a longer sentence with the match for our fruit at the end: kiwi"; 

    long start = System.currentTimeMillis(); 
    int iterations = 10000000; 

    for (int i = 0; i < iterations; i++) { 
     containsWord(words, noMatch); 
     containsWord(words, startMatch); 
     containsWord(words, endMatch); 
    } 

    System.out.println("Contains took " + (System.currentTimeMillis() - start) + "ms"); 
    start = System.currentTimeMillis(); 

    for (int i = 0; i < iterations; i++) { 
     matchesPattern(p,noMatch); 
     matchesPattern(p,startMatch); 
     matchesPattern(p,endMatch); 
    } 

    System.out.println("Regular Expression took " + (System.currentTimeMillis() - start) + "ms"); 
    } 
} 

次のように私が得た結果は以下のとおりであった:

Contains took 5962ms 
Regular Expression took 63475ms 

明らかにタイミングが検索された単語の数に応じて変動します文字列が検索されていますが、はこのような簡単な検索のために正規表現より10倍高速です。

正規表現を使用して別のString内の文字列を検索すると、あなたはナットを壊すためにスレッジハンマーを使用しているので、私はそれがより遅いことに驚かされるべきではないと思います。検索するパターンがより複雑な場合の正規表現を保存します。あなただけの、例えば単語全体だけでなく、サブストリングを、一致させたいのでindexOf()とが仕事をしない場合は、正規表現を使用したい場合があり

一つのケースがありますpearに一致しますが、spearsに一致しません。正規表現はword boundariesという概念を持っているので、このケースをうまく処理します。

\b(apple|orange|pear|banana|kiwi)\b 

\bのみOR式一緒に先頭または単語の終わりとブラケットグループに一致するように言う:

は、このケースでは、私たちにパターンを変更すると思います。あなたのコード内でこのパターンを定義するとき

注意、あなたは別のバックスラッシュでバックスラッシュをエスケープする必要があります。ここでは

Pattern p = Pattern.compile("\\b(apple|orange|pear|banana|kiwi)\\b"); 
7

私は正規表現は、パフォーマンスの面でより良い仕事をするとは思わないが、あなたは以下のようにそれを使用することができます。

Pattern p = Pattern.compile("(apple|orange|pear)"); 
Matcher m = p.matcher(inputString); 
while (m.find()) { 
    String matched = m.group(1); 
    // Do something 
} 
+5

あなたはちょうど読むことができませんか?効率的だとは決して言いませんでした。 –

+1

パフォーマンスは正規表現の長さによって異なります。 1000文字未満の場合は、それに進みます。それ以上の場合は、他の解決策が必要です。たとえば、テキストを分割して単語を分離し、あらかじめ定義された「既知の」単語のハッシュテーブル/セットと照合します。 – AlexR

+2

@deporter答えの目的は、完璧で、光沢のある、世界クラスのソリューションを提供しないように質問を解決する方法のヒントを与えることです。これは簡単に改善することができ、読みやすくするために、200文字列(regexpを使用しないもう1つの理由)があれば、forループを使用して 'StringBuilder'で連結することができます。私の答えは十分な味を提供すると思います。 –

2

私が見つけた最も簡単な解決策は、(ワイルドカードとのマッチング)されています

boolean a = str.matches(".*\\b(wordA|wordB|wordC|wordD|wordE)\\b.*"); 
関連する問題