2012-04-20 9 views
1

TL; DR

私はC#の正規表現を使用してレポートを解析していますが、複数行は名前付きグループで、単一の(複雑な)正規表現パターンを使用してファイル全体を処理し、有効。 (およびCaptureCollection)マッチ複数のインスタンス

私のレポートのセクションが順不同で表示されるか、予測できない方法で欠落しています。

表示される順番に関係なく、どのように一致させることができますか?

はじめ

私はSystem.Text.RegularExpressionsを使用してC#(.NET 3.5)で正規表現を使用してレポートを解析しています。報告書の一つのセクションには、次のようになります。

 Section Z    0 __ base 10 
          2 __ 19/04 20:06:39 
          2 __ 19/04 20:15:49 
          1.8 __ 19/04 20:09:35 
          1.6 __ 19/04 20:07:01 
          1.6 __ 19/04 20:08:29 
    Section 7   0.8 __ base 10 
          8 __ 18/04 21:03:01 
          7.3 __ 18/04 21:02:17 
          3.7 __ 19/04 08:41:09 
          3.4 __ 19/04 00:13:08 
          3.3 __ 18/04 21:02:50 
    Section C    0 __ base 10 
         19.7 __ 19/04 10:25:06 
         11.1 __ 19/04 10:15:01 
          8.8 __ 19/04 10:14:50 
          7.2 __ 19/04 19:51:37 
          6.1 __ 19/04 14:19:47 

私の正規表現は、オプション(?mx)(複数行、IgnorePatternWhitespace)を使用して、全体としてのテキストファイルと一致します。統計セクションにはそれぞれ統計情報のサブ統計があるので、手動で各セクション(?)の非キャプチャグループ((?:match_this_text))を作成し、発生していると思われる順序でパターンに入れています。

(?mx) #Turn on options multiline, ignore whitespace. 
(?: # base 10 statistic sections 
    (?: 
     [\s-[\n\r]]*(?i:Section\sZ)\s+(?<base10_SectionZ>\d+\.\d|\d+)\s__\sbase\s10 
     (?:\r?\n)+ 
     (?:\s+(?<base10_SectionZ_instance>\d+\.\d|\d+)\s__\s(?<base10_SectionZ_instance_time>\d\d/\d\d\s\d\d:\d\d:\d\d)(?:\r?\n)+)+ 
    )? 
    (?: 
     [\s-[\n\r]]*(?i:Section\s7)\s+(?<base10_Section7>\d+\.\d|\d+)\s__\sbase\s10 
     (?:\r?\n)+ 
     (?:\s+(?<base10_Section7_instance>\d+\.\d|\d+)\s__\s(?<base10_Section7_instance_time>\d\d/\d\d\s\d\d:\d\d:\d\d)(?:\r?\n)+)+ 
    )? 
    (?: 
     [\s-[\n\r]]*(?i:Section\sC)\s+(?<base10_SectionC>\d+\.\d|\d+)\s__\sbase\s10 
     (?:\r?\n)+ 
     (?:\s+(?<base10_SectionC_instance>\d+\.\d|\d+)\s__\s(?<base10_SectionC_instance_time>\d\d/\d\d\s\d\d:\d\d:\d\d)(?:\r?\n)+)+ 
    )? 
) 

グループ「はセクションヘッダを」一致する各セクションの非捕捉の最初の行は、2行目はヘッダと統計インスタンス間の改行と一致し、そして第三は、個々の統計インスタンスと一致する(繰り返し、nインスタンス数)。

通報

このレポートを生成するプログラムは、実行されているバージョンに応じて、異なる順序で各セクション(例えばセクションZ、セクション7、セクションC)を出力し、特定のセクションが特定の状況では欠落しています。私が2番目のテストファイルに対して実行したとき、セクションが故障したために失敗しました。

したがって、セクションCは、セクションZ前に発生する可能性が、正規表現パターンは、Zは、C

前に発生することが期待されている基本的に、私は(上記の名前付きグループを使用して)一致し、抽出するために同一の正規表現したい同じそれは上記のテストデータの両方に一致するようにかかわらず、セクションがで表示される順序のデータと、このテストデータ:

 Section 7   0.8 __ base 10 
          8 __ 18/04 21:03:01 
          7.3 __ 18/04 21:02:17 
          3.7 __ 19/04 08:41:09 
          3.4 __ 19/04 00:13:08 
          3.3 __ 18/04 21:02:50 
    Section C    0 __ base 10 
         19.7 __ 19/04 10:25:06 
         11.1 __ 19/04 10:15:01 
          8.8 __ 19/04 10:14:50 
          7.2 __ 19/04 19:51:37 
          6.1 __ 19/04 14:19:47 
    Section Z    0 __ base 10 
          2 __ 19/04 20:06:39 
          2 __ 19/04 20:15:49 
          1.8 __ 19/04 20:09:35 
          1.6 __ 19/04 20:07:01 
          1.6 __ 19/04 20:08:29 
+0

読むファイルは、それらのそれぞれのセクションを並べ替えた後、複数行の文字列やコメントのきちんとした正規表現のレイアウトや使用のために...それに –

+0

賞賛を自分のものを行います! – jessehouwing

+0

私の最終的な解決策は、文字列としてファイル全体に対して単一の巨大な正規表現を使用することではありませんでした。代わりに、私は行を列挙し、行がセクション開始マーカーであるかどうかを再帰的に検索する親子(セクションインスタンス)パターンのスタックを使用します。そうであれば、次の行で子(インスタンス)パターンを試行し、それがうまくいけば、次の行で子を再試行します。子が次の行で失敗すると、一致するものが見つかるまでスタックをポップします。スタックのルートは(。*)であり、ルートにヒットした場合(可能なすべてのパターンを通ります)、そのラインは無視されます。 – Lingnik

答えて

0

正規表現エンジンには何もマッチしないようにしてはいけません。
オプションのものが見つかる前に、多くの「何も見つけられません」ということを見つけ出すことができます。

編集

あなただけのブロックの試合(任意の順序が、シーケンシャルを)したい場合はこのようなものは動作します。修正を加えた今
あなたの方法、:あなたはブロックの試合を気にしない場合は

(?: Section ... (?<sec_a>(?:7|C|Z)) 
(?: Section ... (?<sec_b>(?!\k<sec_a>)(?:7|C|Z) )? 
(?: Section ... (?<sec_c>(?!\k<sec_a>|\k<sec_b>)(?:7|C|Z) )? 
# 
# Then after match check <sec_a/b/c> for its value 


あなたの場合

(?: 
    (?: Section ... (?<sec_7> 7) 
    ) 
| (?: Section ... (?<sec_C> C) 
    )? 
| (?: Section ... (?<sec_Z> Z) 
    ) 
) 
(?: Section ... (?!\k<sec_7>) (?<sec_7> 7))? 
(?: Section ... (?!\k<sec_C>) (?<sec_C> C))? 
(?: Section ... (?!\k<sec_Z>) (?<sec_Z> Z))? 

それは、その後、この方法を因数分解することができる場合OR条件を中心にしています。 だから、それはこのように簡単かもしれない:各試合は「ベース10」セクションの試合はこれでもを低減させることができる

Match m = Regex.Match(input, regex, RegexOptions.IgnorePatternWhitespace); 
while (m.Success) 
{ 
    if (m.Groups["base10_Section7"].Success) { } 
    else 
    if (m.Groups["base10_SectionZ"].Success) { } 
    else 
    if (m.Groups["base10_SectionC"].Success) { } 
    m = m.NextMatch(); 
} 

としてwhileループでチェックする必要があるで

# base 10 statistic sections 
    (?: ..) 
    | 
    (?: ..) 
    | 
    (?: ..) 

。例えば7の場合、Z、Cは単一のチャンク内で結合することができる。
これは、 'base 2'、
または他の形式のように、他の異なる項目が一致するようにOR(|)を残します。 1つのフォームが一致します。とにかくチェックしなければなりません。メモリへ

string input = @" 
    Section Z    0 __ base 10 
          2 __ 19/04 20:06:39 
          2 __ 19/04 20:15:49 
         1.8 __ 19/04 20:09:35 
         1.6 __ 19/04 20:07:01 
         1.6 __ 19/04 20:08:29 
    Section P   16.1 __ base 2 
    Section 7   0.8 __ base 10 
          8 __ 18/04 21:03:01 
         7.3 __ 18/04 21:02:17 
         3.7 __ 19/04 08:41:09 
         3.4 __ 19/04 00:13:08 
         3.3 __ 18/04 21:02:50 
    Section C    0 __ base 10 
         19.7 __ 19/04 10:25:06 
         11.1 __ 19/04 10:15:01 
         8.8 __ 19/04 10:14:50 
         7.2 __ 19/04 19:51:37 
         6.1 __ 19/04 14:19:47 
    Section r   49.2 __ Base 2 
"; 

string regex = @" 
    # base 10 statistic sections 
     (?: 
     [\s-[\n\r]]*(?i:Section\s(?<base10_Section>Z|7|C)\s+(?<Base10>\d+\.\d|\d+)\s__\sbase)\s10 
     (?:\r?\n)+ 
     (?:\s+(?<Instance>\d+\.\d|\d+)\s__\s(?<Time>\d\d/\d\d\s\d\d:\d\d:\d\d)(?:\r?\n)+)+ 
     ) 
    | # Or, base 2 statistic sections 
     (?: 
     [\s-[\n\r]]*(?i:Section\s(?<base2_Section>R|P)\s+(?<Base2>\d+\.\d|\d+)\s__\sbase)\s2 
     (?:\r?\n)+ 
     ) 
    # | Or, something else 

"; 

Match m = Regex.Match(input, regex, RegexOptions.IgnorePatternWhitespace); 
int matchCount = 0; 
while (m.Success) 
{ 
    Console.WriteLine("\nMatch " + (++matchCount) + "\n------------------"); 
    // Check base 10 
    if (m.Groups["base10_Section"].Success) 
    { 
     Console.WriteLine("Section (base10) '" + m.Groups["base10_Section"] + "' = '" + m.Groups["Base10"] + "'\n"); 

     int count = m.Groups["Instance"].Captures.Count; 
     // Instance 
     for (int j = 0; j < count; j++) 
      System.Console.WriteLine(" Instance (" + j + ") = '" + m.Groups["Instance"].Captures[j] + "' "); 
     // Time 
     for (int j = 0; j < count; j++) 
      System.Console.WriteLine(" Time(" + j + ") = '" + m.Groups["Time"].Captures[j] + "' "); 
     // Combined .. 
     for (int j = 0; j < count; j++) 
      System.Console.WriteLine(" Instance,Time (" + j + ") = '" + 
              m.Groups["Instance"].Captures[j] + "' __ '" + 
              m.Groups["Time"].Captures[j] + "' "); 
    } 
    else 
    // Check base 2 
    if (m.Groups["base2_Section"].Success) 
     Console.WriteLine("Section (base2) '" + m.Groups["base2_Section"] + "' = '" + m.Groups["Base2"] + "'\n"); 

    m = m.NextMatch(); 
} 
+0

これは、私が最初に探していたものを最もよく表しています。これは、どのような順序であっても、セクションにマッチする能力でした。セクションの命名規則やそれが表示されるかどうかは決して保証できないので、私は「未知のセットのセクションを、それがどのような順序で表示されても関係なく」探していたはずです。この(と他の)私は、ある巨大な正規表現が適切ではないこと、そしてより深いコード内解析を行わなければならないという認識の道を私に奪われました。 – Lingnik

0

私は1つの巨大なとは異なる正規表現ののカップルを持っている方が良いかもしれないと想像しますこの場合の正規表現。 File.RealAllLinesとし、各行にIf String.Contains("Section")でループします。セクションが含まれている場合は、新しいセクションオブジェクトを作成し、新しいセクションオブジェクト(セクション名とセクションデータ)を読み込むセクション正規表現を実行します。 セクションが含まれていない場合は、追加のセクションデータ用に別の正規表現を実行し、それを現在のセクションオブジェクトに追加します。

1

各セクションをキャプチャしたいだけですか?

これはどうでしょうか?http://regexr.com?30nfd

+0

それはまさに私のものでした。その後、正しいセクションがそこにあることを確認します。 – jessehouwing

0

(Section ..*(?:\r.*){0,5})あなたは、前の結果に、あなたはまだものがないかを確認し、そのように各式を固定するための\ Gオプションを使用する場合があります不要であるあなたのセクションの間にあります。

そして、あなたはセクションのためのより一般的な表現を使用することができます。

(?mx) #Turn on options multiline, ignore whitespace. 
\G 
(?: # base 10 statistic sections 
    (?: 
     [\s-[\n\r]]*(?i:Section\s(Z|7|C))\s+(?<base10_Section>\d+\.\d|\d+)\s__\sbase\s10 
     (?:\r?\n)+ 
     (?:\s+(?<base10_Section_instance>\d+\.\d|\d+)\s__\s(?<base10_Section_instance_time>\d\d/\d\d\s\d\d:\d\d:\d\d)(?:\r?\n)+)+ 
    ) 
) 

は、その後のセクションが重複または欠落していなかったことを確認してください。 See it in action

関連する問題