任意位置的 Perl 可选组

Perl optional group in arbitrary place

我需要捕获序列组,其中一些是可选的。我在 https://www.regular-expressions.info/optional.html 中读到了关于可选的内容,但是 ? 对我不起作用。示例文件:

Code>1<Code
foo
Prod>2<Prod
foo
Type>3<Type

perl -0777ne 'print qq(;;) if /Code>(.*?)<Code.*?Prod>(.*?)<Prod.*?Type>(.*?)<Type/s' < tst.txt 按预期给出 1;2;3

现在我想向第二组添加可选性,如 perl -0777ne 'print qq(;;) if /Code>(.*?)<Code.*?(Prod>(.*?)<Prod)?.*?Type>(.*?)<Type/s' < tst.txt,但它停止打印第二组,给出 1;;(由于嵌套的第三个空与第二个相同,$4 打印 3).

根据 我试过 perl -0777ne 'print qq(;;;) if /Code>(.*?)<Code.*?(Prod>(.*?)<Prod|.*?).*?Type>(.*?)<Type/s' < tst.txt 但又 1;;;3.

是否可以在任何地方随意提取,因为我可以在组之间放置其他内容,如何提取?

编辑: 删除一个 ? perl -0777ne 'print qq(;;;) if /Code>(.*?)<Code.*?(Prod>(.*?)<Prod|.*).*?Type>(.*?)<Type/s' < tst.txt 得到
1; foo Prod>2<Prod foo ;;3 所以捕获第一个和第三个之间的所有内容(看起来第二个选项被提取,而不是 | 之前的一个),而不仅仅是第二个。

编辑: 实施 ?: 建议,现在 perl -0777ne 'print qq(;;;) if /Code>(.*?)<Code.*?(?:Prod>(.*?)<Prod|.*).*?Type>(.*?)<Type/s' < tst.txt 给出 1;;3;

您正在寻找 (?:...) - 捕获组中的 ?: 前缀使其成为一个简单的组,而不是捕获组。我建议每次有一个未捕获的组时都使用它,以使您的意图更清楚。它说,"I'm grouping this, but not keeping it."它甚至可能使运行时间更快,但这不是主要好处。

示例:

perl -0777nE 'say qq[;;] if /Code\>(.*?)\<Code.*?(?:Prod\>(.*?)\<Prod.*?)?Type\>(.*?)\<Type/s' < t

这会打印出 1;2;3

但是,我还建议查看 (?<name>...) 语法,您可以在其中命名您的组并使用 %+(例如,$+{name})按名称而不是位置提取字段.根据我的经验,这使得正则表达式和依赖它的代码更具可读性。