提问人:André Reichelt 提问时间:7/6/2022 最后编辑:André Reichelt 更新时间:7/6/2022 访问量:509
在 c 中通过正则表达式提取多个字符串#
Extract multiple strings via Regex in c#
问:
基于这个问题,我想从文本文件中提取多个数据点。文本文件基本上是带有 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
答:
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)
评论