2017-01-24 3 views
0

string[]の検索文字列を複数行のテキストで使用したいと考えています。テキスト内に存在する文字列パターンの一意の配列を見つける

string[] searchStrings = {"Fizz", "Buzz", "Foo", "Bar"} 

検索文字列の各:,または.が先行し、実際の検索リストは最大100の文字列

そして、私の可能性があり!または?

が続かなければなりませんテキストは次のようになります(しかし、テキストは最大100,000行までです)。FizzBuzz、およびFooがすべて複数回出現し、Barはまったく発生しません。

Lorem ipsum dolor 、Fizz! amet、consipetur adipiscing elit。 Nulla

laoreet .Fizz!ファシリシス。 Mauris :バズ!効能。 Morbi

consectetur hendrerit pretium。 Utテン・マウリス、バズ!結果

convallis。元ラキニアのクスクス・ラシニア・フェリス、マレアス・ルクサス

purus tristique。 Nullam tincidunt dolor sitet metus vehicula、Foo

amet fringilla lacus ultrices。 Maecenas semper .Fizz! le justo molestie、

バズ!結果として。 Donec :Foo? facilisis tellus。 Nunc

pulvinar egestas turpis。 Donecは、Rhincus、Fizz dolor egetのように書かれました。

aliquam orci。 .Foo! tincidunt pellentesque dolor sed mollis。その一例を考えると

は、私は優雅でのパフォーマンスを求めてい {"Fizz","Buzz","Foo"}

返すようにしたいと思います。

私は正規表現が私の最良の選択肢となりますと仮定しているが、私はわからないんだとかどうか:

  • リターンのようなパターンを使用してすべてインスタンスのマッチコレクション:

    [,.:]+(Fizz|Buzz|Foo|Bar)[?!]

    、その後見つけるユニークなマッチ

    各searcオーバー
  • ループ時間文字列とのようなものを使用します。

    Regex.IsMatch(text, string.Format("[,.:]{0}[?!]", searchStrings[i]))

  • それとも私は、各検索文字列の最初のインスタンスを返すように気づいていないよ、いくつかの正規表現構文がありますか?

ユニークなマッチを見つけるには時間がかかる可能性があることを考えると、私はIsMatchアプローチは最速のアプローチになると思いに傾いています。

+0

のようになるでしょう。あなたは既にFizz、Buzz、Foo、またはBarの組み合わせが最初からあることを知っています。 [、。:]と[?!]の間にはっきりとしたマッチをすべて見つけなければなりませんか? – juharr

+0

私はFizz、Buzz、Foo、またはBarを探しているのを知っていますが、私がそれらのどれかを見つけるかどうかはわかりません。私はちょうど存在するものを知りたい。自分の位置や頻度、実際の接頭辞/接尾辞の一致を知る必要はありません。 – ThunderFrame

+0

ええ、IsMatchは可能な一致が少なくても私が行くオプションです。 – juharr

答えて

1

正確なデータの分布にもよりますが、各検索でループする可能性は非常に低いです。あなたは間違いなく非常に大きな文字列を何度も繰り返して行きたくはありません。簡単なベンチマークを作ることができます。

string lorem = @"Lorem ipsum dolor ,Fizz! amet, consectetur 
adipiscing elit. Nulla 
laoreet .Fizz! facilisis. Mauris :Buzz! efficitur nisi. Morbi 
consectetur hendrerit pretium. Ut tempor mauris ,Buzz! consequat 
convallis. Quisque lacinia felis in ex lacinia, luctus malesuada 
purus tristique. Nullam tincidunt dolor sit amet metus vehicula, Foo 
amet fringilla lacus ultrices. Maecenas semper .Fizz! le justo molestie, 
non ultrices Buzz! consequat. Donec :Foo? facilisis tellus. Nunc 
pulvinar egestas turpis. Donec sed ex rhoncus, Fizz dolor eget, 
aliquam orci..Foo! tincidunt pellentesque dolor sed mollis."; 

StringBuilder sb = new StringBuilder(); 
for (int i = 0; i < 10000; ++i) 
{ 
    sb.Append(lorem); 
} 

int lensb = sb.Length; 
Random rnd = new Random(1); 
for (int i = 0; i < 100000; ++i) 
{ 
    sb[rnd.Next(lensb)] = '!'; 
    sb[rnd.Next(lensb)] = '?'; 
    sb[rnd.Next(lensb)] = '.'; 
    sb[rnd.Next(lensb)] = ','; 
    sb[rnd.Next(lensb)] = ':'; 
    sb[rnd.Next(lensb)] = lorem[rnd.Next(lorem.Length)]; 
} 

string sample = sb.ToString(); 

をし、テスト

Regex r = new Regex("[,.:](Fizz|Buzz|Foo|Bar|eeeeeeeeeo|kjkjsh|iousadh|kjlsadh|jfsfs|sdfs)[?!]", RegexOptions.Compiled); 
HashSet<string> matches = new HashSet<string>(); 
foreach (Match match in r.Matches(sample)) 
{ 
    matches.Add(match.Groups[1].Value); 
}//240ms 

悪くない操作を行います。いくつかのダミーデータを作成します。そして今、ループ:

List<string> matches = new List<string>(); 
foreach (string s in new string[] { "Fizz", "Buzz", "Foo", "Bar", "eeeeeeeeeo", "kjkjsh", "iousadh", "kjlsadh", "jfsfs", "sdfs" }) 
{ 
    if (Regex.IsMatch(sample, "[,.:]" + s + "[?!]", RegexOptions.Compiled)) 
    { 
     matches.Add(s); 
    } 
}//890ms 

期待通り、遅いです。しかし、正規表現はおそらくここで最高の演奏者オプションではありません。パフォーマンスが本当に必要な場合は、

enum State { NA, DOT, STR }; 

HashSet<string> ok = new HashSet<string>() { "Fizz", "Buzz", "Foo", "Bar", "eeeeeeeeeo", "kjkjsh", "iousadh", "kjlsadh", "jfsfs", "sdfs" }; 
List<string> matches = new List<string>(); 
int len = sample.Length; 
int start = -1; 
State state = State.NA; 
for (int i = 0; i < len; ++i) 
{ 
    char c = sample[i]; 
    switch (state) 
    { 
     case State.NA: 
      if (c == '.' || c == ',' || c == ':') 
      { 
       start = i; 
       state = State.DOT; 
      } 
      break; 
     case State.DOT: 
      if (c == '.' || c == ',' || c == ':') 
      { 
       start = i; 
       continue; 
      } 
      if (c == '!' || c == '?') 
      { 
       state = State.NA; 
       continue; 
      } 
      state = State.STR; 
      break; 
     case State.STR: 
      if (c == '.' || c == ',' || c == ':') 
      { 
       start = i; 
       state = State.DOT; 
       continue; 
      } 
      if (c == '!' || c == '?') 
      { 
       state = State.NA; 
       string substr = sample.Substring(start + 1, i - start - 1); 
       if (ok.Contains(substr)) 
       { 
        matches.Add(substr); 
        ok.Remove(substr); 
       } 
       continue; 
      } 
      break; 
    } 
}//30ms 
+0

興味深い。テキストが短い文字列の配列で、各文字列の長さが平均20〜30文字、空白、長さが短い、長めの文字列ではなく、長めの文字列の場合、戦略がどのように変化するのだろうか? – ThunderFrame

+0

この場合、ループアプローチはメモリの局所性を向上させますが、短絡の利点を失います。テストは結果が遅いと言います。私が測定したタイミングは0〜50文字の100000サンプルに対して120ms、660ms、20msでした。私はHashSetとのマッチを変更し、最後のコードでは 'ok'を変更しませんでした。正直言って私はなぜ手作りの状態自動化がここで正規表現よりもずっと速いのか分かりません。おそらく正規表現の実装はここではいくらか非効率です。しかし、いつものように、私はむしろ実際のデータのタイミングを再テストしたいと思います。 –

関連する問題