【问题标题】:Perl regex captures non-capturing groupsPerl 正则表达式捕获非捕获组
【发布时间】:2018-05-08 10:12:29
【问题描述】:

我正在使用 perl 来解析 CSV 文件。我使用正则表达式而不是任何库来解析它。我知道,有可用的 CSV 解析器库,而且不止一个,但我刚刚决定要使用 REGEX。

我为此创建了一个我认为非常不错且有效的正则表达式。我最初创建了其他应用程序,它们仅使用正则表达式来解析文件。我想在这种情况下重复使用它。

我想用perl的美把它放在一行里:

my $text = '"",hi there,"","2018-04-23,\" 13:14:53",,hostname,mac,"ipaddress",199';

my @data = $text =~ m/(?:^|,)(?:"(|.*?[^\\])"|([^,]*))(?:|$)/g;

但是,当我在单行中执行此操作时,perl 正则表达式甚至会捕获非捕获组。

这是一个测试代码:

my $text = '"",hi there,"","2018-04-23,\" 13:14:53",,hostname,mac,"ipaddress",199';

my @data = $text =~ m/(?:^|,)(?:"(|.*?[^\\])"|([^,]*))(?:|$)/g;
foreach (@data) { print "a --${_}--\n"; }

while ($text =~ m/(?:^|,)(?:"(|.*?[^\\])"|([^,]*))(?:|$)/cg) {
    print "b --${1}${2}--\n";
}

“a”转储的结果是:

a ----
a ----
a ----
a --hi there--
a ----
a ----
a --2018-04-23,\" 13:14:53--
a ----
a ----
a ----
a ----
a --hostname--
a ----
a --mac--
a --ipaddress--
a ----
a ----
a --199--

您可以看到额外的空行,而不是“b”转储的正确结果:

b ----
b --hi there--
b ----
b --2018-04-23,\" 13:14:53--
b ----
b --hostname--
b --mac--
b --ipaddress--
b --199--

有没有人遇到过这个问题? 感谢您的回答/想法/错误发现。

【问题讨论】:

  • 说真的 - 正则表达式是这个工作的错误工具。我知道你说“你想使用它”。但是... CSV 是上下文相关的 - 它可以包含嵌套引号、换行符等。regex 不是上下文相关的,因此它永远不会穷举。 Text::CSV 擅长它的工作。
  • “我想使用 perl 的美,把它放在一行中” “Perl 的美”不在于编写难以理解的代码来复制经过验证的功能测试模块。
  • 您的字符串 "",hi there,"","2018-04-23,\" 13:14:53",,hostname,mac,"ipaddress",199 不是有效的 CSV 数据。
  • (?:|$) 没有任何意义:它总是匹配的。

标签: regex perl regex-group


【解决方案1】:

当我发布我的问题时,我意识到问题不是非捕获组,而是实际捕获组,其中只有一个具有值,而另一个当时是空的。

罪魁祸首是这部分正则表达式:

(?:"(|.*?[^\\])"|([^,]*))

branch-reset 功能替换非捕获组后一切正常:

(?|"(|.*?[^\\])"|([^,]*))

所以最终工作正确的单行是:

my @data = $text =~ m/(?:^|,)(?|"(|.*?[^\\])"|([^,]*))(?:|$)/g;

希望有人会发现此信息有用。

【讨论】:

  • TBH 您的问题是您使用的是regex 而不是Text::CSV。我知道你“决定你只想使用正则表达式”但是......那是用锤子把螺丝钉进去。当然,它可以工作,但它永远不会是丑陋的。
  • 嗯,我真的不认为这种单线丑陋。这是一种 perl 语法。正如我还提到的,我之前为其他工具、软件创建了正则表达式,我无法在其中修改代码。该软件仅采用正则表达式和输出格式,我使用“$ 1 $ 2”,所以我没有注意到这个问题。补充一点,我发布这个问题更多是出于好奇。我想知道是否还有其他人遇到过同样的情况。我不敢相信这会是 perl 中的错误,这就是我在这里问的原因。我已经准备好使用Text::CSV
  • @petom:当您基本上是在捍卫一个仍然存在错误的相当坚不可摧的正则表达式模式时,我对您的评论收到的赞成票感到惊讶。我还怀疑Text::CSV::XS 会慢一些。不知道同意你的人是否愿意发表评论?
  • @Borodin 我发布它不是为了 CSV 解析。 CSV 只是一个用例。这篇文章的主要目的是正则表达式的“特殊”或“魔力”。我相信人们也遇到过类似的问题,当他们有多个子组,其中一个排除另一个时,他们希望每次都能获得 1 美元的结果。我以前在多个项目中都需要这个,但通常“1 美元”的解决方法就足够了。我在 python 和其他脚本语言中使用了类似的正则表达式(方法,不一定是 CSV 解析)。这个案例让我终于通过正则表达式文档进行了一些搜索。
  • @petom:(?|...) 构造并不是一个特殊的构造。 $1$2 将导致 未初始化 警告,因为其中一个或其他捕获必须是 undef。如果您的帖子只是为了庆祝 Perl 的可爱,那么它就离题了,而且问题本身并没有说明这一点。
猜你喜欢
  • 1970-01-01
  • 2021-09-06
  • 1970-01-01
  • 2018-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-17
  • 2019-01-12
相关资源
最近更新 更多