15

次の正規表現を使用しています

JOINTS.*\s*(?:(\d*\s*\S*\s*\S*\s*\S*)\r\n\s*)*

次のタイプのデータ:

 JOINTS               DISPL.-X               DISPL.-Y               ROTATION


     1            0.000000E+00           0.975415E+01           0.616921E+01
     2            0.000000E+00           0.000000E+00           0.000000E+00

アイデアは、2 つのグループを抽出することです。それぞれに行が含まれています (ジョイント番号、1、2 などで始まります)。C# コードは次のとおりです。

string jointPattern = @"JOINTS.*\s*(?:(\d*\s*\S*\s*\S*\s*\S*)\r\n\s*)*";
MatchCollection mc = Regex.Matches(outFileSection, jointPattern );
foreach (Capture c in mc[0].Captures)
{
    JointOutput j = new JointOutput();
    string[] vals = c.Value.Split();
    j.Joint = int.Parse(vals[0]) - 1;
    j.XDisplacement = float.Parse(vals[1]);
    j.YDisplacement = float.Parse(vals[2]);
    j.Rotation = float.Parse(vals[3]);
    joints.Add(j);
}

ただし、これは機能しません。キャプチャされた 2 つのグループ (内側のグループ) を返すのではなく、1 つのグループ (列ヘッダーを含むブロック全体) を返します。なぜこれが起こるのですか?C# は、キャプチャされていないグループを別の方法で処理しますか?

最後に、正規表現はこれを行うための最良の方法ですか? (私は今、2つの問題を抱えているように感じています。)

4

4 に答える 4

12

mc[0].Capturesと同等mc[0].Groups[0].Capturesです。 Groups[0]常に一致全体を参照するため、それに関連付けられたキャプチャは 1 つだけになります。探している部分はグループ #1 にキャプチャされているため、 を使用する必要がありますmc[0].Groups[1].Captures

ただし、正規表現は 1 回の試行で入力全体と一致するように設計されているため、Matches()メソッドは常に 1 つの Match のみを含む MatchCollection を返します (一致が成功した場合)。Match()代わりに次を使用することもできます。

  Match m = Regex.Match(source, jointPattern);
  if (m.Success)
  {
    foreach (Capture c in m.Groups[1].Captures)
    {
      Console.WriteLine(c.Value);
    }
  }

出力:

1            0.000000E+00           0.975415E+01           0.616921E+01
2            0.000000E+00           0.000000E+00           0.000000E+00
于 2013-03-02T06:12:03.363 に答える
3

Regex重いものを持ち上げてテキストを解析するために使用することはしません。

var data = @"     JOINTS               DISPL.-X               DISPL.-Y               ROTATION


         1            0.000000E+00           0.975415E+01           0.616921E+01
         2            0.000000E+00           0.000000E+00           0.000000E+00";

var lines = data.Split('\r', '\n').Where(s => !string.IsNullOrWhiteSpace(s));
var regex = new Regex(@"(\S+)");

var dataItems = lines.Select(s => regex.Matches(s)).Select(m => m.Cast<Match>().Select(c => c.Value));

ここに画像の説明を入力

于 2013-03-02T03:38:34.827 に答える
1

2つの問題があります。繰り返し部分(?:...)が適切に一致していません。は.*貪欲ですべての入力を消費するため、繰り返し部分が一致することはありません。

代わりにこれを使用してください:

JOINTS.*?[\r\n]+(?:\s*(\d+\s*\S*\s*\S*\s*\S*)[\r\n\s]*)*

これには貪欲でない先頭部分があり、行一致部分が(タイトルの途中ではなく)新しい行で開始することを保証し、[\r\n\s]*改行が期待どおりでない場合に使用します。

個人的には、これには正規表現を使用しますが、正規表現が好きです:-)文字列の構造が常に[title] [newline] [newline] [lines]であることがわかっている場合は、おそらくもっと簡単です(少ない場合)柔軟)改行で分割し、それに応じて処理します。

最後に、regex101.comまたは他の多くの正規表現テストサイトの1つを使用して、正規表現のデバッグに役立てることができます。

于 2013-03-02T03:22:19.787 に答える
1

値だけをキャプチャして、残りを無視してみませんか。値を取得する正規表現を次に示します。

string data = @"JOINTS DISPL.-X DISPL.-Y ROTATION
 1 0.000000E+00 0.975415E+01 0.616921E+01
 2 0.000000E+00 0.000000E+00 0.000000E+00";

string pattern = @"^
\s+
 (?<Joint>\d+)
\s+
 (?<ValX>[^\s]+)
\s+
 (?<ValY>[^\s]+)
\s+
 (?<Rotation>[^\s]+)";

var result = Regex.Matches(data, pattern, RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture)
                  .OfType<Match>()
                  .Select (mt => new
                  {
                    Joint = mt.Groups["Joint"].Value,
                    ValX  = mt.Groups["ValX"].Value,
                    ValY  = mt.Groups["ValY"].Value,
                    Rotation = mt.Groups["Rotation"].Value,
                  });
/* result is
IEnumerable<> (2 items)
Joint ValX ValY Rotation
1 0.000000E+00 0.975415E+01 0.616921E+01
2 0.000000E+00 0.000000E+00 0.000000E+00
*/
于 2013-03-02T03:38:53.667 に答える