关于sed:在BASH中,如何用`{(anything)::(anything)}`替换匹配`{(anything)}`的模式?

How to replace patterns matching `{ + (anything) + }` with `{ + (anything) + :: + (anything) + }` in BASH?

我有一个带有一些文本的文件,其中一些重要的项目标有大括号和右括号,例如:

1
2
3
4
Once upon a {time}, there lived a rabbit.
The {rabbit lived} in a small house.
One day, the {rabbit visited }the {mountains}.
In the mountains, he {found} a tree with 10{,000} branches.

我需要用{x::x}替换{x}形式的任何项目,例如:

1
2
3
4
Once upon a {time::time}, there lived a rabbit.
The {rabbit lived::rabbit lived} in a small house.
One day, the {rabbit visited ::rabbit visited }the {mountains::mountains}.
In the mountains, he {found::found} a tree with 10{,000::,000} branches.
  • 每个开口{在同一行上都有一个匹配的}
  • 大括号永不分开。
  • 大括号永远不会嵌套。
  • {}之间可能出现任何类型的符号。

我尝试了sed的几种方法,但是没有任何效果,例如:

1
sed 's/{(.*)}/{&::&}/g' file.txt

如何替换括号中的所有项目,例如{some word}具有模式{some word::some word}


这是解决方法

1
2
3
4
5
6
sed 's/{\\([^}]*\\)}/{\\1::\\1}/g' file

Once upon a {time::time}, there lived a rabbit.
The {rabbit lived::rabbit lived} in a small house.
One day, the {rabbit visited ::rabbit visited }the {mountains::mountains}.
In the mountains, he {found::found} a tree with 10{,000::,000} branches.

解释

  • [^}]*匹配非}字符
  • \\(...\\)将捕获在括号内指定的字符,而\\\\ 1将用于引用第一个匹配项,这是regex的一部分。

如果可以使用perl

1
2
3
4
5
$ perl -ple 's/{(.*?)}/{$1::$1}/g' file
Once upon a {time::time}, there lived a rabbit.
The {rabbit lived::rabbit lived} in a small house.
One day, the {rabbit visited ::rabbit visited }the {mountains::mountains}.
In the mountains, he {found::found} a tree with 10{,000::,000} branches.

它匹配花括号{...}中的所有内容(非贪婪),然后将其替换为所需的字符串{$1::$1}


awk变体:

1
2
3
4
5
6
$ awk 'BEGIN{ORS=""} NR%2==0{$0="{"$0"::"$0"}"} 1' RS='[{}]' file.txt

Once upon a {time::time}, there lived a rabbit.
The {rabbit lived::rabbit lived} in a small house.
One day, the {rabbit visited ::rabbit visited }the {mountains::mountains}.
In the mountains, he {found::found} a tree with 10{,000::,000} branches.


您应该使用

1
sed 's/\\([^{]*{\\)\\([^}]*\\)\\(}.*\\)/\\1\\2::\\2\\3/'

未测试