在 c 中通过正则表达式提取多个字符串#

Extract multiple strings via Regex in c#

提问人:André Reichelt 提问时间:7/6/2022 最后编辑:André Reichelt 更新时间:7/6/2022 访问量:509

问:

基于这个问题,我想从文本文件中提取多个数据点。文本文件基本上是带有 Key: Value 方案的 C#。每个键值对都在一行上。我创建了以下代码:string

var matches = Regex.Matches(
    pageText,
    "^Ort Lieferadresse: (?<deliveryAdress>.*)$|^Referenz: (?<reference>.*)$|^Lademittel: (?<loading>.*)$|^Plombennummer: (?<plombe>.*)$|^Bemerkung: (?<remarks>.*)$",
    RegexOptions.Multiline);

这有效,但是我在提取实际捕获时遇到了问题,因为它返回了五个匹配项。我也尝试使用这种方法,但除了第一组之外,所有人都被找到了。Match

有没有办法一次性返回所有捕获?

下面是一些示例数据:

Verladeplan
Erzeugt von: moehlerj
Erzeugt am: 01.03.2022
Ausliefertermin: 03.03.2022-01:00:00
Darstellung Verladeplan
Ladeinformationen
Ausliefertermin: 03.03.2022-01:00:00
Ort Lieferadresse: Foo
Referenz: Bar
Lademittel: 40' Container
Lademeter: 1176.000
Gesamtanzahl Paletten: 24
Gesamtbruttogewicht: 6669.0
Plombennummer: keine, da Abholung im LKW
Bemerkung: Kennzeichen: AB12345 / CD67890
Containernummer:
TARA:
Seite 1 von 2
C# 正则表达式 匹配

评论


答:

2赞 Olivier Jacot-Descombes 7/6/2022 #1

如果为这些行定义了特定顺序,则将正则表达式 OR 替换为正则表达式换行符。您还可以删除行的开头和结尾以及以下几行的周围:|\n^$\n

var match = Regex.Match(
    pageText,
    @"^Ort Lieferadresse: (?<deliveryAdress>.*)\r\nReferenz: (?<reference>.*)\r\nLademittel: (?<loading>.*)\r(.|\r|\n)*\nPlombennummer: (?<plombe>.*)\r\nBemerkung: (?<remarks>.*)$",
    RegexOptions.Multiline);

// Test
if (match.Success) {
    Console.WriteLine(match.Groups["deliveryAdress"].Value);
    Console.WriteLine(match.Groups["reference"].Value);
    Console.WriteLine(match.Groups["loading"].Value);
    Console.WriteLine(match.Groups["plombe"].Value);
    Console.WriteLine(match.Groups["remarks"].Value);
} else {
    Console.WriteLine("no match");
}

这使它找到一个匹配项。


如果信息可以按任何顺序显示,我建议根本不使用正则表达式,并使用以下命令加载文件:

IEnumerable<string> lines = File.ReadLines(path);

然后,将信息插入字典。这使您可以轻松访问所需的数据。此外,字典会自动包含所有可用的标签。

var dict = lines
    .Select(l => (text: l, index: l.IndexOf(": ")))
    .Where(t => t.index > 0)
    .Select(t => (key: t.text[0..t.index], value: t.text[(t.index + 2)..]))
    .DistinctBy(kv => kv.key) // Because Ausliefertermin occurrs twice
    .ToDictionary(kv => kv.key, kv => kv.value);

此测试

Console.WriteLine($"Ort Lieferadresse = {dict["Ort Lieferadresse"]}");
Console.WriteLine($"Referenz = {dict["Referenz"]}");
Console.WriteLine($"Lademittel = {dict["Lademittel"]}");
Console.WriteLine($"Plombennummer = {dict["Plombennummer"]}");
Console.WriteLine($"Bemerkung = {dict["Bemerkung"]}");

收益 率

Ort Lieferadresse = Foo
Referenz = Bar
Lademittel = 40' Container
Plombennummer = keine, da Abholung im LKW
Bemerkung = Kennzeichen: AB12345 / CD67890

评论

0赞 Wiktor Stribiżew 7/6/2022
我知道这些线不一定是连续的,可以按任何顺序出现。实际上,我们需要 OP 的更多输入。此外,在 Windows 中,行尾是 CRLF,而不仅仅是 LF。
0赞 André Reichelt 7/6/2022
@WiktorStribiżew 现在,线路是固定的。但是,将来顺序可能会发生变化,我不想每次发生这种情况时都手动调整我的代码。
2赞 Wiktor Stribiżew 7/6/2022 #2

你可以使用

var text = "Ort Lieferadresse: deliveryAdress\r\nReferenz: reference\r\nLademittel: loading\r\nPlombennummer: plombe\r\nBemerkung: remarks";
var pattern = @"^Ort Lieferadresse: (?<deliveryAdress>[^\r\n]*)\r?$|^Referenz: (?<reference>[^\r\n]*)\r?$|^Lademittel: (?<loading>[^\r\n]*)\r?$|^Plombennummer: (?<plombe>[^\r\n]*)\r?$|^Bemerkung: (?<remarks>[^\r\n]*)\r?$";
var results = Regex.Matches(text, pattern, RegexOptions.Multiline)
        .Cast<Match>()
        .SelectMany(m => m.Groups.Skip(1))
        .Where(n => n.Success);
foreach (Group grp in results)
    Console.WriteLine("{0}: {1}", grp.Name, grp.Value);

查看 C# 演示 yielding

deliveryAdress: deliveryAdress
reference: reference
loading: loading
plombe: plombe
remarks: remarks

首先,为了支持 CRLF 行尾并牢记 .NET 正则表达式中的含义,我建议在行锚点末尾替换并添加可选的 CR 模式 ()。..*[^\r\n]*\r?$

然后,获取 返回的所有匹配对象的列表,获取每个匹配对象的属性,不包括第 0 个项(这是我们不需要的整个匹配项),并且只会保留参与匹配的组。.Cast<Match>()Regex.Matches(text, pattern, RegexOptions.Multiline).SelectMany(m => m.Groups.Skip(1))Groups.Where(n => n.Success)