我正在学习perl正则表达式,并尝试合并捕获组和指定字符串的第n次出现。
比如说我有下面的话:
title="alpha" lorem ipsum lorem ipsum name="beta" Morbi posuere metus purus name=delta Curabitur ullamcorper finibus consectetur name=sigma
我想将title
属性更改为第n个name=
之后的字符串,例如sigma
,同时保留其间的所有内容。此外,name=
可能带有双引号,例如name="beta"
或name=sigma
。
第一次出现name=
:
title="beta" lorem ipsum lorem ipsum Morbi posuere metus purus name=delta Curabitur ullamcorper finibus consectetur name=sigma
第二次出现name=
:
title="sigma" lorem ipsum lorem ipsum name="beta" Morbi posuere metus purus name=delta Curabitur ullamcorper finibus consectetur
我用途:
find . -type f -exec perl -pi -w -e 's/(title=)"?[^"\s]*"?(.*) name="?([^"\/]+)"?/$1"$3"$2/' \{\} \;
这适用于第一次出现的name=
。
我不知道如何修改它来指定name=
的第n次出现。我知道指定第n次出现的基础知识(例如 * 将第二个abc
替换为xyz
*),...
s/abc/ ++$count == 2 ? "xyz" : "abc" /eg
...但在将其集成到上面的代码中时遇到了问题。如何指定第n个name=
并移动其下面的捕获组来替换title
属性?
4条答案
按热度按时间oyt4ldly1#
您可以使用模式在
{n}
部分中设置一个手动量词,并可以选择重复key=value对以获得您感兴趣的量词。模式匹配:
(title=)"?[^\s="]+"?
捕获组1,匹配title=
并匹配替换后不想保留的值(
捕获组2\h+
匹配1个以上空格(?:.*?[^\s=]+=[^\s=]+){0}
n 次重复前面的键=值对.*?
尽可能不匹配任何字符)
关闭组2[^\s=]+=
匹配除空格字符或=
之外的任何字符1次以上,然后匹配关键部分的=
"?([^\s="]+)"?
捕获可选双引号之间的group 3中除空格字符=
或"
以外的1个以上字符\h*
匹配可选的尾随空格请参见0 repetitions、1 repetition和2 repetitions的正则表达式演示。
运行
{0}
、{1}
和{2}
命令中的模式将文件中的行更改为:
5lwkijsr2#
您可以使用此
perl
解决方案:这里
(?:.*?\h+name=){N}
匹配子模式的N
次出现,该子模式是任何文本,后跟1+空格,后跟文本name=
。此子模式重复了{N}
次,如示例所示。Online Code Demo
p1tboqfb3#
可以通过执行多遍而不是一遍征服所有正则表达式来简化
完整示例
在测试中,我使用
file.txt
和问题中的行,命令行输入
2
使它查找第二个“name”。如果出于某种原因需要,整个过程可以写在一行上。
这会两次搜索相同的模式(在
while
条件和它的主体中),所以从这个意义上说,它是低效的。不过这也不是太糟糕,因为模式相当简单,如果需要的话,可以进行优化,而这种低效只有在做了 * 很多 * 或者使用非常复杂的模式时才能感觉到。但是这是两个具有相同模式的正则表达式,看起来并不令人愉快。这样做的好处是(相对)简单,所有模式都寻求一个孤立的简单短语。
uqxowvwt4#
不要在一个正则表达式中完成所有操作,而是分步骤进行:
1.将所有名称提取到@m数组中;
1.用所需名称替换标题;
1.移除名称定义。
sigma
是第二个名称。我会说它是第三个,而delta
是第二个。