从替换列表中替换文本。增加了复杂性:反斜杠

从替换列表中替换文本。增加了复杂性:反斜杠

我有一个文件 A,其中包含一对字符串,每行一个:

\old1 \new1
\old2 \new2
.....

我想遍历文件 A,并对文件 B 中的每一行执行全局替换(例如“\old1 -> \new1”)。使用 sed 或 perl -pi -e 无需反斜杠即可轻松完成替换,具体操作如下:

while read -r line
do
 set -- $line
 sed -i -e s/$1/$2/g target
done < replacements

但是,我不知道如何在替换字符串中逐字制作sedperl处理反斜杠。有一个干净的解决方案吗?

答案1

您需要转义正则表达式中的所有特殊字符,不仅是反斜杠,还有分隔[.*^$s(对于 sed)。在 Perl 中,使用该quotemeta函数。

您的尝试的另一个问题是,当您运行 时set -- $line,shell 会执行自己的扩展:除了分词之外,它还执行通配符,因此如果您的行包含并且当前目录中有名为anda* b*的文件,那么您将替换为。您需要在这种方法中关闭通配符。a1a2a1a2set -f

这是一个将替换列表直接修改为 sed 参数列表的解决方案。它假设源文本和替换文本中没有空格字符,但应正确处理除空格和换行符之外的任何字符。第一个替换\在需要保护的字符之前添加了 ,第二个替换将每行从foo bar 变为-e s/foo/bar/g。警告,未经测试。

set -f
sed_args=$(<replacement sed -e 's~[/.*[\\^$]~\\&~g' \
                            -e 's~^\([^ ]*\)  *\([^ ]*\).*~-e s/\1/\2/g~')
sed -i $sed_args target

在 Perl 中,如果您只是让 Perl 直接读取替换文件,那么引用方面的问题就会减少。再次,未经测试。

perl -i -pe 'BEGIN {
   open R, "<replacement" or die;
   while (<R>) {
       chomp;
       ($from, $to, @ignored) = split / +/;
       $s{$from} = $to;
   }
   close R;
   $regexp = join("|", map {quotemeta} keys %s);
}
s/($regexp)/$s{$1}/ego'

答案2

对于简单的情况,有简单的解决方案,所以如果你碰巧有干净、简单、核心的单词,没有 .?+*{}()[]\/ 以及可能更奇特的 sed-stuff,你可以传输对列表使用 sed 到 sed 命令文件:

sed -re 's,(^\\| \\|$),/,g;s/^/s/;s/$/g/' pairs.txt > pairs.sed
sed -f pairs.sed input > output

答案3

这是尝试使用带有模式替换的参数扩展来转义反斜杠。

$ set -- \\foo \\bar
$ echo $1
\foo
$ echo ${1/\\/\\\\}
\\foo
$ echo "This is \foo to me"
This is \foo to me
$ echo "This is \foo to me" | sed s/${1/\\/\\\\}/${2/\\/\\\\}/
This is \bar to me
$ 

答案4

您可能需要预处理替换列表,以转义诸如斜杠之类的内容,这些内容在放入正则表达式时将具有特殊含义。首先转义它们,然后使用它们进行迭代。

根据您用来执行替换的函数,有时您可以添加一些标志来按字面意思处理字符串。如果您展示您的部分解决方案,也许我们可以建议完成它的正确方法。

相关内容