2017-07-25 12 views
3
の文字列またはStringBuilderの検索

C#でawk '/start/,/end/' fileと同じ機能を実行する関数(必要に応じてヘルパー関数のセットとともに)を作成したいすべての最後の試合は、最初に終了するよりもむしろ。パターン範囲/ start// end/

は、我々が持っているとしましょう:

# cat text 
"13:08:30:5276604 Main: 41044 - 48.7617 M-- Other PIDS 2 - 79.1016 M" 
"13:08:30:5736962 Main: 41044 - 48.7617 M-- Other PIDS 2 - 79.1016 M" 
"13:08:30:6227343 Main: 41044 - 48.7617 M-- Other PIDS 2 - 79.1016 M" 
"13:08:30:6757752 Main: 41044 - 48.7617 M-- Other PIDS 2 - 79.1016 M" 
"13:08:30:7208103 Main: 41044 - 48.7617 M-- Other PIDS 2 - 79.1016 M" 
"13:08:30:7668739 Main: 41044 - 48.7617 M-- Other PIDS 2 - 79.1016 M" 
"13:08:30:8129079 Main: 41044 - 48.7617 M-- Other PIDS 2 - 79.1016 M" 

予想:

"13:08:30:6227343 Main: 41044 - 48.7617 M-- Other PIDS 2 - 79.1016 M" 
"13:08:30:6757752 Main: 41044 - 48.7617 M-- Other PIDS 2 - 79.1016 M" 
"13:08:30:7208103 Main: 41044 - 48.7617 M-- Other PIDS 2 - 79.1016 M" 
"13:08:30:7668739 Main: 41044 - 48.7617 M-- Other PIDS 2 - 79.1016 M" 

AWK出力:私が最初に私はちょうど2つの条件pattern_1 | pattern_2で正規表現マッチを得るかもしれないと思った

# awk '/13:08:30:62/,/13:08:30:7/' text 
"13:08:30:6227343 Main: 41044 - 48.7617 M-- Other PIDS 2 - 79.1016 M" 
"13:08:30:6757752 Main: 41044 - 48.7617 M-- Other PIDS 2 - 79.1016 M" 
"13:08:30:7208103 Main: 41044 - 48.7617 M-- Other PIDS 2 - 79.1016 M" 

ただし、一致する値の間に値がある場合、これは機能しません。

また、C#StringBuilderクラスに.indexOf().lastIndexOf()メソッドがないことも発見しました(私はJavaでもう少し経験がありますので、C#を使用していないことがわかるまでこれらを使用することを考えていました)。私はこれらの方法を持っておらず、おそらくそれらを実装する必要があるので、私はこれが行くべきアプローチかどうか尋ねたいと思っていました。このセクションでは、広範な検索が必要な場合はStringを使用することを提案しています:MSDN - 私は確かにそれを使用することもできます。 StringBuilderを使用することを選択しました。なぜなら、文字列連結が常に実行されるからです。文字列(多くの連結)を構築するときにstringbuilderタイプを使用する必要がありますが、次に検索するとstringタイプに変換されますか?

私はこれも演奏者になりたいと思いますし、そのようにする方法を提案するのはすばらしいことです。一般的なガイダンスと実装の詳細は高く評価されます。

+2

あなたの問題は、どのように特定のでしょうか?これはこの特別な場合にのみ有効か、awkと同じスコープで動作すべきか? – MetaColon

+2

'StringBuilder'は文字列_building_のためのものです。最初にそれを構築し、文字列全体を生成し、 'String'関数を使って検索します。 –

+0

@MetaColon - 特定の場合だけでなく、より一般性が望まれます。私は次のように指定します: "utf8文字列の中に存在する2つのパターンは、最初のパターンで始まり2番目のパターンで終わるテキストを見つけます。"/end /パターンの行全体を追加する追加の要件を追加することができます。 @D Stanley - あなたが正しい軌道にいることを確認するのは、いつも良いことです。 –

答えて

0

大きなファイルを処理する必要がある場合は、StreamReaderをよく使用し、ReadLineメソッドを使用して1行に処理します。これにより、StringBuilderを使用しているときと同じように、完全なファイルがメモリに格納されるのを防ぐことができます。実装でabstract TextReaderを使用すると、文字列を(ファイル)ストリームとして使用できます。

終了を確認するには、Regex classを使用します。 Matchメソッドは、Successプロパティを持つインスタンスを返します。これは、一致が見つかった場合にtrueになります。

論理を達成するには、3つの状態があると思います。開始点を見つける前に、終了点を見つける前に、まだ終了点を見つけています。私はイテレータでこれをyieldキーワードを使って実装することを選択しました。これは、ステートマシンをほぼ無料で利用できるようにするためです。ここで

は実装です:

void Main() 
{ 
    // use a streamreader to read characters 
    // the .ctor accpets an Encoding as second parameter 
    using(var sr = new StreamReader(@"sample.txt")) 
    { 
     ReadFromBeginToEnd("13:08:30:62","13:08:30:7",sr); 
    } 

    var text [email protected]" 
13:08:30:6227343 Main: 41044 - 48.7617 M-- Other PIDS 2 - 79.1016 M 
13:08:30:6757752 Main: 41044 - 48.7617 M-- Other PIDS 2 - 79.1016 M 
13:08:30:7208103 Main: 41044 - 48.7617 M-- Other PIDS 2 - 79.1016 M 
13:08:30:7668739 Main: 41044 - 48.7617 M-- Other PIDS 2 - 79.1016 M"; 
    using(var sr = new StringReader(text)) 
    { 
     ReadFromBeginToEnd("13:08:30:62","13:08:30:7", sr); 
    } 
} 

// enumerate over the lines from the streamreader 
// accepting two regexes, start and end 
IEnumerable<string> FromBeginToEnd(TextReader rdr, Regex start, Regex end) 
{ 
    // 1st state 
    var line = rdr.ReadLine(); // initial read, null means we're done 
    // read the lines until we hit our start match 
    while(line != null && !start.Match(line).Success) 
    { 
     // don't return these lines 
     line = rdr.ReadLine();  
    } 
    // 2nd state 
    // read the lines while we didn't hit our end match 
    while(line != null && !end.Match(line).Success) 
    { 
     // return this line to the caller 
     yield return line; 
     line = rdr.ReadLine();  
    } 
    // 3rd state 
    // read the lines while we find our end match 
    while(line != null && end.Match(line).Success) 
    { 
     // return this line to the caller 
     yield return line; 
     line = rdr.ReadLine();  
    } 
    // iterator is done 
    yield break; 
} 

// take a start and end string that can be compiled to a regex 
// and a file (fullpath) 
void ReadFromBeginToEnd(string start, string end, TextReader reader) 
{ 
    // loop over the lines that mach the criteria 
    // FromBeginToEnd is our custom enumerator 
    foreach(var line in FromBeginToEnd(reader, new Regex(start), new Regex(end))) 
    { 
     // write to standard out 
     // but this can be an StreamWriter.WriteLine as well. 
     Console.WriteLine(line); 
    } 
}