【问题标题】:How to count matches for a named capture group in Perl如何在 Perl 中计算命名捕获组的匹配项
【发布时间】:2018-01-12 16:21:44
【问题描述】:

我有一个拼凑在一起的 Perl 命令,它在文件上运行正则表达式查找和替换。它工作得很好,但即使生成的文件相同,也会有“修改”文件的不幸副作用。这是有道理的,因为它正在用自己替换匹配项。我们不能这样做,因为结果是make 管道的一部分,并且每次运行都会导致整个重建。

我现在想运行一个命令来获取特定命名捕获组的匹配计数,以便在实际运行第一个命令之前测试是否需要替换任何内容。

通过带有一些 bash 变量的 bash 执行命令:perl -0777 -i -pe '$cnt=0;s{('$PASSTHROUGH'|'$REPLACE')}{$+{PASSTHROUGH}?$+{PASSTHROUGH}:(++$cnt,'$REPLACEMENT')")}peg; END{print "$cnt\n"}'

再一次,这很好用,并且给了我实际替换的数量,因为 $cnt 仅在三元运算符的 else 分支中增加。如果我只为 $REPLACE 模式运行匹配,我将不会得到正确的数字,因为它通常会匹配 $PASSTHROUGH 组中的内容。

我怀疑有一种方法可以检索特定组的计数,但我不知道 Perl 或术语,所以我正在努力寻找如何将这个命令更改为 not 进行替换,而是仅将匹配项计数到 $REPLACE 子模式。它是一个命名组:(?<REPLACE>some-regex-pattern)

【问题讨论】:

  • 我不确定你想用直通做什么,它匹配但没有改变任何东西?那为什么还要匹配呢?如果正确,您只需删除左侧的 PASSTHROUGH 并使用 s{SEARCH}{REPLACE} 的返回值
  • 每次正则表达式匹配时都会重置特殊映射 %+,因此除了使用 ++$cnt 之外没有其他方法可以获取计数,也许可以使用 \K 来避免替换直通匹配,例如 @987654332 @
  • @Eily 因为$REPLACE 会匹配$PASSTHROUGH 匹配的内容。 $PASSTHROUGH 是一个相当复杂的模式,由其他几个子模式组成并使用递归,据我所知,没有它就不可能做我需要的事情。
  • @NahuelFouilleul 我的问题不在于计数本身 ++$cnt 对我来说工作正常。我需要一种在不实际修改文件的情况下获取$cnt 的方法。我会调查\K。谢谢。
  • @BradAllred,在您显示的代码中,我们看不到文件已修改,也许可以删除 -i 选项以不修改文件

标签: regex perl pcre


【解决方案1】:

问题更新后编辑

  • -0777 表示整个文件被读取一次(输入记录分隔符 undef)
  • -i :就地编辑文件(如sed -i),必须删除以避免修改文件
  • -p : 打印行

下面的命令应该只打印匹配的数量

perl -0777 -ne '$cnt=@a=m{('$PASSTHROUGH'(*SKIP)(?!)|'$REPLACE')}pg;print "$cnt\n"'

它的做法不同:

  • 模式交替的原则是先匹配不能满足我们想要的东西
  • (*SKIP) : 是一个回溯控制动词,它防止正则表达式引擎在匹配失败后回溯,这是正常做的
  • (?!) :与(*FAIL) 相同

【讨论】:

  • 我将使用完整的 Perl 命令更新问题。我很抱歉。
  • 好的请注意,由于文件末尾的print "$cnt" 写入文件,文件总是被修改
  • 我不太确定。运行此文件后,文件不包含任何此类内容。只有模式所做的替换。 git 没有显示其他更改,此类更改会导致编译错误。
  • 我已经更新了缺少的开关。我相信-0777 以某种方式处理整个文件而不是逐行处理。
  • 非常感谢。我相信这行得通!请允许我在接受之前再进行一些测试。您介意解释一下-ne 选项吗?
猜你喜欢
  • 2019-05-06
  • 1970-01-01
  • 2022-01-12
  • 2014-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多