Perl正则表达式捕获组和重排模式[重复]

bwleehnv  于 2022-11-15  发布在  Perl
关注(0)|答案(3)|浏览(151)

此问题在此处已有答案

Perl regex capture groups(1个答案)
三个月前关门了。
我使用perl regex捕获组来替换大量文件的模式。
文件示例1:

title="alpha" lorem ipsum lorem ipsum name="beta"

文件示例2:

title="omega" Morbi posuere metus purus name="delta"

用于
第一次
使用

find . -type f -exec perl -pi -w -e 's/title="(?'one'.*?)"(?'three'.*?)name="(?'two'.*?)"/title="\g{two}"\g{three}/g;' \{\} \;

(Note(1)标题和名称的属性值是未知变量,以及(2)title="alpha"name="beta"之间的内容不同。)
我还在学习Perl正则表达式。我做错了什么?

k10s72fa

k10s72fa1#

以下perl命令行应该可以正常工作:

perl -pe 's/(title=)"?[^"\s]*"?(.*) name="?([^"\s]+)"?/$1"$3"$2/' file

title="beta" lorem ipsum lorem ipsum
title="delta" Morbi posuere metus purus

说明:

  • (title=):匹配title=并在组#1中捕获
  • "?[^"\s]+"?:匹配带引号的非空格字符串
  • (.*):匹配0个或多个任意字符并在组#2中捕获
  • name="?:匹配name=文本,后跟可选的"
  • ([^"\s]+):匹配带引号的非空格字符串并在组#3中捕获
  • "?:可选"
  • $1"$3"$2:更换零件

RegEx Demo

bxpogfeg

bxpogfeg2#

一点语法:用(?<name>pattern)捕获,然后在模式之外使用用$+{name}捕获(定界符可以变化);我在perlre看到的整个正则表达式

s{ title="(?<t>[^"]+)" (?<text>.*?) name="(?<n>[^"]+)" }
 {title="$+{n}"$+{text}}x

在问题中尝试的\g{name}语法在模式本身内部使用(如果在第一次捕获它的相同模式中进一步需要它);但在匹配端之后,因此在替换端或在正则表达式之后,从%+变量中检索匹配项。
[^"]是一个取反的字符类,匹配除"之外的任何字符。末尾的修饰符/x使它忽略里面的文字空格,这样我们就可以使用它们来提高可读性。
一个完整的例子,上面的正则表达式,运行在命令行

echo title=\"alpha\" lorem ipsum lorem ipsum name=\"beta\"  | perl -wpe
's{title="(?<t>[^"]+)"(?<text>.*?)name="(?<n>[^"]+)"}{title="$+{n}"$+{text}}'

(为了便于阅读,分为两行)。它将打印

title="beta" lorem ipsum lorem ipsum

不确定在问题中捕获的第一个模式是什么,但可能比显示的更多,因此也在这里捕获到$+{t}中。
而且,这个问题以一种特殊的方式使用了这些引号。一个 * 可以 * 将'分隔的字符串串串在一起用于一个命令行程序(perl -wE'say''"hi"'是有效的)。这个问题中的例子是有效的,因为什么是“barewords”(one等)碰巧在regex中,在那里它们是可以的,作为模式。但我建议不要弄乱它(如果这是意图)。

wlp8pajw

wlp8pajw3#

***第一个解决方案:***因为您使用的是shell的find命令,所以如果您对awk代码没有问题,那么就用GNU awk编写并测试它。

下面是以下代码中使用的正则表达式的Online demo

awk -v s1="\"" '
match($0,/(title=)"[^"]*" (.*)name="([^"]*)"/,arr){
  print arr[1] s1 arr[3] s1,arr[2]
}
'  Input_file

***说明:***这里的简单说明是使用GNU awkmatch函数;它允许我们在其中使用regex来找到所需的输出。在这里我使用regex (title=)"[^"]*" (.*)name="([^"]*)",它创建了3个捕获组,它们的值被存储到名为arr的数组中,索引为'1,2,3,其中包含捕获组的值。然后在打印这些值的同时,我根据OP所需的输出来打印它们。
***第二个解决方案:***在sed中,使用相同的正则表达式和-E(ERE)启用选项,请尝试以下代码。

sed -E 's/^(title=)"[^"]*" (.*)name="([^"]*)"/\1"\3" \2/' Input_file

相关问题