使用正则表达式替换文件中的(一个或)两个不同模式

使用正则表达式替换文件中的(一个或)两个不同模式

假设一个input.txt文件包含多个字符串,如下所示:

[[foo>a|a]]
[[foo>b|b]]
[[foo>c|c]]

我想替换为:

:foo:`a`
:foo:`b`
:foo:`c`

我想我可以用sedor来达到这个结果rg(我从未使用过awk)。

但该文件还包含其他字符串,如下所示:

[[foo>a|d]]
[[foo>b|e]]
[[foo>c|f]]

我想替换为:

:foo:`d <a>`
:foo:`e <b> `
:foo:`f <c>`

我所有的尝试都失败了,因为我不知道如何同时处理两种不同的模式。

您知道一些方法可以实现后一个结果(顺便说一句,前一个结果)吗?

答案1

使用标准sed 语法:

sed '
  s/^\[\[\(.*\)>\(.*\)|\2\]\]$/:\1:`\2`/; t
  s/^\[\[\(.*\)>\(.*\)|\(.*\)\]\]$/:\1:`\3 <\2>`/'

答案2

通过环视,您可以检查周围的字符串是否|相同。例如:

$ cat ip.txt 
[[foo>a|d]]
[[foo>b|e]]
[[foo>c|f]]

# same as: rg -NP '\[\[([^>]+)>([^|]+)\|(?!\2])([^|]+)]]' -r ':$1:`$3 <$2>`'
$ perl -pe 's/\[\[([^>]+)>([^|]+)\|(?!\2])([^|]+)]]/:$1:`$3 <$2>`/' ip.txt 
:foo:`d <a>`
:foo:`e <b>`
:foo:`f <c>`

(?!\2])是一个否定的前瞻断言,以确保周围的字符串|不同。


要实现这两者,您可以在带有标志的替换部分中使用 Perl 代码e

$ cat ip.txt
[[foo>a|a]]
[[foo>b|b]]
[[foo>c|c]]

[[foo>a|d]]
[[foo>b|e]]
[[foo>c|f]]

$ perl -pe 's/\[\[([^>]+)>([^|]+)\|([^|]+)]]/":$1:`$3" . ($2 eq $3 ? "`" : " <$2>`")/e' ip.txt 
:foo:`a`
:foo:`b`
:foo:`c`

:foo:`d <a>`
:foo:`e <b>`
:foo:`f <c>`

这里,将根据周围的字符串是否相同来($2 eq $3 ? "`" : " <$2>`")选择字符串。|

答案3

看来我们可以把这个任务分成 2-3 个独立的部分。首先,我们挤压 ( -s) 并用 , 替换一些字符tr,以创建输出的“轮廓”,然后用 ased我们进行两次单独的替换,一个用于两个字符匹配,一个用于两个字符不同时。

< file tr -s '[<>|]' ':::``' | sed -E 's/(.)`\1`/`\1`/; s/([^:])`(.)`/`\2 <\1>`/'

测试:

$ cat file
[[foo>a|a]]
[[foo>b|b]]
[[foo>c|c]]
[[foo>a|d]]
[[foo>b|e]]
[[foo>c|f]]

$ <file tr -s '[<>|]' ':::``' | sed -E 's/(.)`\1`/`\1`/;s/([^:])`(.)`/`\2 <\1>`/' 
:foo:`a`
:foo:`b`
:foo:`c`
:foo:`d <a>`
:foo:`e <b>`
:foo:`f <c>`

答案4

使用awk来管理处理两种给定的格式:

awk -F'\\[\\[|\\]\\]|>|\\|' '{
    print $1, $2, "`" ($3==$4? $3 : $4" <"$3">") "`";
}' OFS=':' infile

测试输入:

[[foo>a|a]]
[[foo>bb|bb]]
[[foo>c|ccc]]
[[foo>aaaa|d]]
[[foo>b|ddd]]
[[foo>cccc|fff]]

输出:

:foo:`a`
:foo:`bb`
:foo:`ccc <c>`
:foo:`d <aaaa>`
:foo:`ddd <b>`
:foo:`fff <cccc>`

相关内容