4

私の質問は、Java の正規表現、特に特定の検索パターンに対する複数の一致に関連しています。取得する必要があるすべての情報は 1 行にあり、IP アドレスにマップされるエイリアス (SA など) が含まれています。それぞれをコンマで区切ります。それぞれを抽出する必要があります。

SA "239.255.252.1", SB "239.255.252.2", SC "239.255.252.3", SD "239.255.252.4"

私の正規表現は次のようになります。

Pattern alias = Pattern.compile("(\\S+)\\s+\"(\\d+\\.\\d+\\.\\d+\\.\\d+)\"");  
Matcher match = alias.matcher(lineInFile)  
while(match.find()) {  
   // do something  
}

これは機能しますが、この小さなコードを導入してからプログラムの速度が少し遅くなりましたが (< 1 秒)、違いに気付くには十分なため、完全には満足していません。

だから私の質問は、私はこれを正しい方法で行っていますか? while(match) ループを必要としない、より効率的またはおそらく軽量なソリューションはありますか? および/またはパターン/マッチャークラス?

4

6 に答える 6

1

行にエイリアス定義以外のものが含まれていない可能性がある場合は、.match()代わりに ofを使用すると.find()、一致しない検索が高速化される可能性があります。

于 2010-09-29T09:28:46.540 に答える
0

残念ながら、あなたのコードはすでにかなり効率的に見えます。これが私のバージョンです:

Matcher match = Pattern
                .compile("(\\w+)\\s+\"(\\d+\\.\\d+\\.\\d+\\.\\d+)\"")
                .matcher(lineInFile);  
while(match.find()) {  
    //do something  
}

2 つのマイクロ最適化があります。

  1. インライン化された追加の変数にパターンを保持する必要はありません
  2. エイリアスについては、スペース以外の文字ではなく、単語の文字を検索します

実際、このような多くの処理を行ってもパターンが変わらない場合は、コンパイルされたパターンを一定に保つ必要があります。

private static final Pattern PATTERN = Pattern
            .compile("(\\w+)\\s+\"(\\d+\\.\\d+\\.\\d+\\.\\d+)\"");

Matcher match = PATTERN.matcher(lineInFile);  
while(match.find()) {  
    //do something  
}

更新: RegExrで時間をかけて、有効な IP アドレスのみをおまけとして検出するより具体的なパターンを考え出しました。私はそれが地獄のように醜いことを知っていますが、バックトラッキングのほとんどを排除するので、かなり効率的だと思います:

([A-Z]+)\s*\"((?:1[0-9]{2}|2(?:(?:5[0-5]|[0-9]{2})|[0-9]{1,2})\.)
{3}(?:1[0-9]{2}|2(?:5[0-5]|[0-9]{2})|[0-9]{1,2}))

(読みやすくするためにラップされています。すべてのバックスラッシュはJavaでエスケープする必要がありますが、OPのテスト文字列を使用してRegExrでテストできます)

于 2010-09-29T09:36:44.013 に答える
0

"(\\S{2})\\s+\"((\\d{1,3}\\.){3}\\d{1,3})\""IP アドレスをより明示的に指定することにより、正規表現を次のように改善できます。

を使用したパフォーマンスを試してくださいStringTokenizer。正規表現は使用しません。(レガシー クラスの使用が心配な場合は、そのソースを見て、それがどのように行われているかを確認してください。)

StringTokenizer st = new StringTokenizer(lineInFile, " ,\"");
while(st.hasMoreTokens()){
    String key = st.nextToken();
    String ip = st.nextToken();
    System.out.println(key + " ip: " +  ip);
}
于 2010-09-29T09:38:46.933 に答える
0

そのコードで 1 秒未満の違いに気付いた場合、入力文字列には約 100 万 (少なくとも 10 万) のエントリが含まれている必要があります。これはかなり公平なパフォーマンスだと思いますが、独自の専用パーサーを作成せずに大幅に最適化する方法がわかりません。

于 2010-09-29T11:42:13.093 に答える
0

Pattern オブジェクトをプリコンパイルして再利用することは (IMO) 最も効果的な最適化である可能性があります。パターンのコンパイルは、コストのかかるステップになる可能性があります。

Matcher インスタンスの再利用 (例: の使用reset(CharSequence)) は役立つかもしれませんが、大きな違いが生じるとは思えません。

正規表現自体を大幅に最適化することはできません。考えられる高速化の 1 つは、 に置き換えること(\d+\.\d+\.\d+\.\d+)です([0-9\.]+)。これは潜在的なバックトラック ポイントの数を減らすので役立つかもしれませんが、確認するにはいくつかの実験を行う必要があります。明らかな欠点は、有効な IP アドレスではない文字シーケンスに一致することです。

于 2010-09-29T11:13:28.097 に答える
0

これによりパフォーマンスが大幅に向上するかどうかはわかりませんが、最初に行うこともできます

string.split(", ") // separate groups

その後

string.split(" ?\"") // separate alias from IP address

試合で。

于 2010-09-29T10:00:01.400 に答える