1

レガシー システムの位置ベース ファイルを解析します。ファイル内の各列の列幅は固定で、各行の長さは最大 80 文字です。問題は、行の長さが分からないことです。最初の 5 列しか入力していない場合もあれば、すべての列が使用されている場合もあります。

80文字すべてが使用されていることがわかっている場合は、次のように簡単に実行できます。

^\s*
 (?<a>\w{3})
 (?<b>[ \d]{2})
 (?<c>[ 0-9a-fA-F]{2})
 (?<d>.{20})
 ...

ただし、これの問題は、最後の列が欠落している場合、行が一致しないことです。最後の列は、その列の最大値よりも少ない文字数になることさえあります。

例を見る

Text to match         a   b  c  d
"AQM45A3A text   " => AQM 45 A3 "A text   "  //group d has 9 chars instead of 20
"AQM45F5"          => AQM 45 F5              //group d is missing
"AQM4"             => AQM  4                 //group b has 1 char instead of 2
"AQM4  ASome Text" => AQM  4  A "Some Text"  //group b and c only uses one char, but fill up the gap with space
"AQM4FSome Text"   => No match, group b should have two numbers, but it is only one.
"COM*A comment"    => Comments do not match (all comments are prefixed with COM*)
"       "          => Empty lines do not match

これに一致する正規表現をどのように設計すればよいですか?

編集 1

この例では、解析したい各行が AQM で始まっています

  • 列 a は常に位置 0 から始まります
  • 列 b は常に位置 3 から始まります
  • 列 c は常に位置 5 から始まります
  • 列 d は常に位置 7 から始まります

列がすべてのスペースを使用していない場合、ファイルはスペースで構成されています 使用されている最後の列のみをトリミングできます

編集2 より明確にするために、データがどのように見えるかの例と列の定義をここに同封します(質問で前述した例は非常に単純化されていることに注意してください)

AQM の例 AQMの定義

4

4 に答える 4

3

ここで正規表現を使用するのが正しいかどうかはわかりません。私があなたの構造を理解していれば、あなたは次のようなものが欲しい

if (length >= 8) 
   d = everything 8th column on
   remove field d
else
   d = empty

if (length >= 6)
   c = everything 6th column on
   remove field c
else
   c = empty

など。正規表現でできるかもしれませんが、おそらくかなり不自然です。

于 2013-08-21T14:32:33.400 に答える
1

つまり、言い換えると、あなたの例では一連の文字があり、最初の 3 つはグループ A に属し、次の 2 つはグループ B に属し、次に 2 はグループ C に、20 はグループ D に属しますが、これほど多くの要素ではありません。

試してみてください:

(?<a>\w{0,3})(?<b>[ \d]{0,2})(?<c>[ 0-9a-fA-F]{0,2})(?<d>.{0,20})

基本的に、これらの数は、固定サイズではなく、グループの上限になりました。

編集、最後のコメントを反映する: 関連するすべての行が「AQM」で始まることがわかっている場合は、グループ A を次のように置き換えることができます(?<a>AQM)

別の編集: 代わりにこれを試してみましょう。

(?<a>AQM)(?<b>[ \d]{2}|[ \d]$)(?<c>[ 0-9a-fA-F]{0,2})(?<d>.{0,20})
于 2013-08-21T14:40:29.820 に答える
0

おそらく、このような関数を使用して、文字列を列の値に分割できます。コメント文字列を解析せず、80 文字未満の文字列を処理できます。ただし、列の内容は検証されません。たぶん、値を使用するときにそれを行うことができます。

/// <summary>
/// Break a data row into a collection of strings based on the expected column widths.
/// </summary>
/// <param name="input">The width delimited input data to break into sub strings.</param>
/// <returns>
/// An empty collection if the input string is empty or a comment.
/// A collection of the width delimited values contained in the input string otherwise.
/// </returns>
private static IEnumerable<string> ParseRow(string input) {
    const string COMMENT_PREFIX = "COM*";
    var columnWidths = new int[] { 3, 2, 2, 3, 6, 14, 2, 2, 3, 2, 2, 10, 7, 7, 2, 1, 1, 2, 7, 1, 1 };
    int inputCursor = 0;
    int columnIndex = 0;
    var parsedValues = new List<string>();

    if (String.IsNullOrEmpty(input) || input.StartsWith(COMMENT_PREFIX) || input.Trim().Length == 0) {
        return parsedValues;
    }

    while (inputCursor < input.Length && columnIndex < columnWidths.Length) {
        //Make sure the column width never exceeds the bounds of the input string. This can happen if the input string doesn't end on the edge of a column.
        int columnWidth = Math.Min(columnWidths[columnIndex++], input.Length - inputCursor);
        string columnValue = input.Substring(inputCursor, columnWidth);
        parsedValues.Add(columnValue);
        inputCursor += columnWidth;
    }
    return parsedValues;
}
于 2013-08-22T01:55:05.503 に答える