0

我需要使用 c# 和正则表达式解析固定宽度的记录。每条记录都包含许多固定宽度的字段,每个字段都可能具有重要的验证规则。我遇到的问题是在固定宽度的字段边界上应用匹配。

如果没有规则,很容易将长度为 13 的固定宽度字符串分成 4 个部分,如下所示:

(?=^.{13}$).{1}.{5}.{6}.{1}

这是一个示例字段规则:字段可以是所有空格或以 [AZ] 开头并右填充空格。字母之间不能出现空格

如果该字段是我唯一需要验证的内容,我可以使用它:

(?=^[A-Z ]{5}$)([ ]{5}|[A-Z]+[ ]*)

当我将此验证添加为较长列表的一部分时,我必须从前瞻中删除 ^ 和 $,并且我开始获得长度不为 5 的匹配项。

这是完整的正则表达式以及一些应该匹配和不匹配表达式的示例文本。

(?=^[A-Z ]{13}$)A(?=[A-Z ]{5})([ ]{5}|(?>[A-Z]{1,5})[ ]{0,4})(?=[A-Z ]{6})([ ]{6}|(?>[A-Z]{1,6})[ ]{0,5})Z

如何实施规则,以便对于每个字段,紧接下一个 XX 字符用于匹配并确保匹配不重叠?

应该匹配的行:

ABCDEFGHIJKLZ
A           Z
AB          Z
A     G     Z
AB    G     Z
ABCDEF      Z
ABCDEFG     Z
A     GHIJKLZ
AB    GHIJKLZ

不应匹配的行:

AB D        Z
AB D F      Z
AB   F      Z
A     G I   Z
A     G I  LZ
A     G    LZ
AB   FG    LZ
AB D FG     Z
AB   FG I   Z
AB D FG i   Z

以下 3 不应该匹配但可以匹配。

AB   FG     Z
AB   FGH    Z
AB  EFGH    Z

编辑:

为清楚起见,带有命名捕获的通用解决方案(基于 Ωmega 的答案):

(?<F1>F1Regex)(?<=^.{Len(F1)})
(?<F2>F2Regex)(?<=^.{Len(F1+F2)})
(?<F3>F3Regex)(?<=^.{Len(F1+F2+F3)})
               ...
(?<Fn>FnRegex)

另一个例子:正则表达式和零宽度正回溯之间的空格 (?<= 是为了清楚起见。

(?<F1>\d{2})    (?<=^.{2})
(?<F2>[A-Z]{5}) (?<=^.{7})
(?<F3>\d{4})    (?<=^.{11})
(?<F4>[A-Z]{6}) (?<=^.{17})
(?<F5>\d{4})
4

4 回答 4

1

如果输入字符串的大小是固定的,那么您可以使用前瞻和后视匹配特定位置,如下所示:

(?<=^.{s})(?<fieldName>.*)(?=.{e}$)

在哪里:

  • s = 起始位置
  • e = 字符串长度 - 匹配长度 - s

如果您连接多个正则表达式,例如这个,那么您将获得具有特定定位的所有字段。

例子

  • 固定长度:10
  • 字段 1:开始 0,长度 3
  • 字段 2:开始 3,长度 5
  • 字段 3:开始 8,长度 2

使用此正则表达式,忽略空格:

var match = Regex.Match("0123456789", @"
    (?<=^.{0})(?<name1>.*)(?=.{7}$)
    (?<=^.{3})(?<name2>.*)(?=.{2}$)
    (?<=^.{8})(?<name3>.*)(?=.{0}$)",
        RegexOptions.IgnorePatternWhitespace)

var field1 = match.Groups["name1"].Value;
var field2 = match.Groups["name2"].Value;
var field3 = match.Groups["name3"].Value;

您可以放置​​任何您想要匹配字段的规则。

.*都用过,但你可以在那里放任何东西。

示例 2

var match = Regex.Match(" 1a any-8888", @"
    (?<=^.{0})(?<name1>\s*\d*[a-zA-Z])(?=.{9}$)
    (?<=^.{3})(?<name2>.*)(?=.{4}$)
    (?<=^.{8})(?<name3>(?<D>\d)\k<D>*)(?=.{0}$)
    ",
        RegexOptions.IgnorePatternWhitespace)

var field1 = match.Groups["name1"].Value; // " 1a"
var field2 = match.Groups["name2"].Value; // " any-"
var field3 = match.Groups["name3"].Value; // "8888"

这是你的正则表达式

我测试了所有这些,但是这个样本是你说不应该通过的样本,但是通过了……这一次,它不会通过:

var match = Regex.Match("AB   FG     Z", @"
    ^A
    (?<=^.{1})  (?<name1>([ ]{5}|(?>[A-Z]{1,5})[ ]{0,4}))  (?=.{7}$)
    (?<=^.{6})  (?<name2>([ ]{6}|(?>[A-Z]{1,6})[ ]{0,5}))  (?=.{1}$)
    Z$
    ",
        RegexOptions.IgnorePatternWhitespace)

// no match with this input string
于 2012-10-20T18:16:32.867 回答
1
Match match = Regex.Match(
  Regex.Replace(text, @"^(.)(.{5})(.{6})(.)$", "$1,$2,$3,$4"),
  @"^[A-Z ],[A-Z]*[ ]*,[A-Z]*[ ]*,[A-Z ]$");

在此处检查此代码。

于 2012-10-20T19:15:36.417 回答
0

我之前已经发布过这个,但这个答案更具体到你的问题,而不是一概而论。

这可以按照您想要的方式解决您在问题中提出的所有案例。

测试您问题中所有案例的程序

class Program
{
    static void Main()
    {
        var strMatch = new string[]
                      {
                          // Lines that should match:
                          "ABCDEFGHIJKLZ",
                          "A           Z",
                          "AB          Z",
                          "A     G     Z",
                          "AB    G     Z",
                          "ABCDEF      Z",
                          "ABCDEFG     Z",
                          "A     GHIJKLZ",
                          "AB    GHIJKLZ",
                      };


        var strNotMatch = new string[]
                      {
                          // Lines that should not match:
                          "AB D        Z",
                          "AB D F      Z",
                          "AB   F      Z",
                          "A     G I   Z",
                          "A     G I  LZ",
                          "A     G    LZ",
                          "AB   FG    LZ",
                          "AB D FG     Z",
                          "AB   FG I   Z",
                          "AB D FG i   Z",

                          // The following 3 should not match but do.
                          "AB   FG     Z",
                          "AB   FGH    Z",
                          "AB  EFGH    Z",
                      };

        var pattern = @"
                ^A
                (?<=^.{1})  (?<name1>([ ]{5}|(?>[A-Z]{1,5})[ ]{0,4}))  (?=.{7}$)
                (?<=^.{6})  (?<name2>([ ]{6}|(?>[A-Z]{1,6})[ ]{0,5}))  (?=.{1}$)
                Z$
                ";

        foreach (var eachStrThatMustMatch in strMatch)
        {
            var match = Regex.Match(eachStrThatMustMatch,
                pattern, RegexOptions.IgnorePatternWhitespace);

            if (!match.Success)
                throw new Exception("Should match.");
        }


        foreach (var eachStrThatMustNotMatch in strNotMatch)
        {
            var match = Regex.Match(eachStrThatMustNotMatch,
                pattern, RegexOptions.IgnorePatternWhitespace);

            if (match.Success)
                throw new Exception("Should match.");
        }
    }
}
于 2012-10-20T21:02:58.947 回答
0

我认为可以通过单个正则表达式模式来验证它

^[A-Z ][A-Z]*[ ]*(?<=^.{6})[A-Z]*[ ]*(?<=^.{12})[A-Z ]$

如果您还需要捕获所有此类组,请使用

^([A-Z ])([A-Z]*[ ]*)(?<=^.{6})([A-Z]*[ ]*)(?<=^.{12})([A-Z ])$
于 2012-10-20T19:20:50.577 回答