我需要使用C#和正则表达式来解析固定宽度记录。每个记录都包含许多固定宽度字段,每个字段可能具有非平凡的验证规则。我遇到的问题是在固定宽度范围边界上应用匹配项。
没有规则,很容易将长度13的固定宽度字符串分解为4个部分:
(?=^.{13}$).{1}.{5}.{6}.{1}
这是一个示例字段规则:字段可以是所有空间,也可以从[A-Z]开始,然后用空格填充。在字母之间不可能发生空间
如果该字段是我唯一要验证的东西,我可以使用它:
(?=^[A-Z ]{5}$)([ ]{5}|[A-Z]+[ ]*)
当我添加此验证作为更长列表的一部分时,我必须从lookahead中删除 ^和$,然后开始获得不长的匹配项。
这是完整的正则态度以及一些应匹配且不匹配表达式的示例文本。
(?=^[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)
另一个示例:正则和零宽的正回本书(?&lt; =为清晰。
)(?<F1>d{2}) (?<=^.{2})
(?<F2>[A-Z]{5}) (?<=^.{7})
(?<F3>d{4}) (?<=^.{11})
(?<F4>[A-Z]{6}) (?<=^.{17})
(?<F5>d{4})
如果输入字符串已固定为大小,则可以使用look-aheads和look-behinds匹配特定位置,例如:
(?<=^.{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
Match match = Regex.Match(
Regex.Replace(text, @"^(.)(.{5})(.{6})(.)$", "$1,$2,$3,$4"),
@"^[A-Z ],[A-Z]*[ ]*,[A-Z]*[ ]*,[A-Z ]$");
检查此代码在此处。
我认为有可能通过单条正则态度进行验证
^[A-Z ][A-Z]*[ ]*(?<=^.{6})[A-Z]*[ ]*(?<=^.{12})[A-Z ]$
如果您还需要捕获所有此类组,请使用
^([A-Z ])([A-Z]*[ ]*)(?<=^.{6})([A-Z]*[ ]*)(?<=^.{12})([A-Z ])$
我以前已经发布了此内容,但是这个答案更适合您的问题,而不是概括。
这解决了您在问题中提出的所有情况,即您想要的方式。
程序以测试您的问题中的所有情况
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.");
}
}
}