【发布时间】:2019-01-07 13:03:27
【问题描述】:
我有一个文件,其中包含以下格式的正则表达式列表和替换文字字符串:
OLD_REGEXP_1 NEW_STRING_1
OLD_REGEXP_2 NEW_STRING_2
...
我想将多个文件*.txt 中与OLD_REGEXP_X 匹配的所有字符串替换为NEW_STRING_X。
我相信这是一个常见的问题,之前应该有人做过类似的事情,但我只是找不到用 bash 编写的现有解决方案。
例如:
Tom Thompson
Billy Bill&Ted
goog1e\.com google.com
https?://www\.google\.com https://google.com
输入:
Tom and Billy are visiting http://www.goog1e.com
预期输出:
Thompson and Bill&Ted are visiting https://google.com
主要挑战是:
- 要替换的字符串由 POSIX 扩展正则表达式描述,而不是文字,并且任何不是 POSIX ERE 元字符的字符,包括经常被某些工具用作正则表达式分隔符的
/,必须被视为字面意思。 - 替换字符串是文字,可以包含任何文字字符,包括像
&和\1这样的字符,它们经常在替换字符串中用作反向引用元字符,但在这种情况下必须是文字。 - 替换必须按照它们在映射文件中出现的顺序发生,因此如果我们在映射文件中按该顺序有 A->B 和 B->C,并且 A 出现在要更改的文本文件中,那么输出将包含“C”代替“A”,而不是“B”。
【问题讨论】:
-
新旧字符串是否也可能包含特殊字符,如
*、+、[、]、(、)、&等? -
@anubhava,是的,旧字符串也可能包含
?,! -
那么它们是正则表达式还是文字字符串?在后一种情况下,您需要反斜杠或以其他方式中和
*、[等(但不是特别是!,或者,取决于sed方言,甚至必须是?) -
我认为我们总是可以将旧字符串视为正则表达式。但我不太确定
/在sed或awk中的工作原理,所以无论如何我都在逃避它们。 -
每一个存在的旧字符串都应该被新字符串替换,如果新字符串以后匹配到另一个旧字符串,也应该以同样的方式处理。