我有事要完成。我需要将所有出现的 & 内部或之间替换<ex>
</ex>
为 #。实际例子如下:
a & b & c <ex> a & b & c </ex> a & b & c
再次,我需要替换所有出现的 & 内部<ex>
和之前</ex>
预期输出:
a & b & c <ex> a # b # c </ex> a & b & c
请发布关于你们如何做到这一点的解释。
编辑#1
请只向我提供一个sed
解决方案,因为我将在 AS400 系统上运行它,并且无法安装 Perl 或任何其他解释器。
答案1
<ex>...</ex>
如果每行只出现一次:
sed -e :1 -e 's@\(<ex>.*\)&\(.*</ex>\)@\1#\2@;t1'
如果可能有多个出现并且它们不嵌套(或者它们嵌套并且您只想替换&
最深的出现中的):
sed '
s|_|_u|g # replace all underscores with "_u"
s|(|_o|g # replace all open parentheses with "_o"
s|)|_c|g # replace all close parentheses with "_c"
s|<ex>|(|g # replace all open ex tags with "("
s|</ex>|)|g # replace all close ex tags with ")"
:1 # a label
s/\(([^()]*\)&\([^()]*)\)/\1#\2/g
# find:
# an open parentheses,
# some non-parentheses chars (captured),
# an ampersand,
# some non-parentheses chars (captured) and
# a close parentheses,
# replace with
# the first captured text,
# an octothorpe
# the second captured text,
# globally in the current record.
t1 # if there was a successful replacement, goto label "1",
# else carry on
s|(|<ex>|g # restore open tags
s|)|</ex>|g # restore close tags
s|_o|(|g # restore open parentheses
s|_c|)|g # restore close parentheses
s|_u|_|g # restore underscores
'
如果它们可能嵌套并且您想将其替换为封闭的:
sed '
s|_|_u|g;s|(|_o|g;s|)|_c|g
s|<ex>|(|g;s|</ex>|)|g;:1
s/\(([^()]*\)(\([^()]*\))\([^()]*)\)/\1_O\2_C\3/g;t1
:2
s/\(([^()]*\)&\([^()]*)\)/\1#\2/g;t2
s|(|<ex>|g;s|)|</ex>|g
s|_O|<ex>|g;s|_C|</ex>|g
s|_o|(|g;s|_c|)|g;s|_u|_|g'
答案2
Perl(需要 5.14 版本)来救援:
perl -pe 's%(<ex>.*?</ex>)% $1 =~ s/&/#/gr %eg'
在旧版本中,您必须更详细:
perl -pe 's%(<ex>.*?</ex>)% ($_x = $1) =~ s/&/#/g; $_x %eg'
说明:将<ex>
标签之间的所有内容放入$1
, 内$1
,将 & 替换为#。
答案3
另一个 perl 命令,
$ perl -pe 's/&(?=(?:(?!<ex>|<\/ex>).)*<\/ex>)/#/g' file
a & b & c <ex> a # b # c </ex> a & b & c
在解释上述命令之前,我将解释一下负前瞻和正前瞻实际上会做什么。
在正则表达式中(?=...)
意味着积极的前瞻。环视(即;正向和负向前瞻、正向和负向向后查找)将进行零宽度匹配。也就是说,它不会匹配任何字符。通常正向和负向前瞻用于条件检查目的。也(?:...)
称为非捕获组。也就是说,非捕获组内的模式只会进行匹配操作。它不会捕获任何字符。
(?!<ex>|<\/ex>)
无法匹配字符串<ex>
或</ex>
。(?:(?!<ex>|<\/ex>).)
它实际上的意思是,它首先查找后面的三个字符或四个字符,并确保后面的三个或四个字符不能是<ex>
或</ex>
。.
只有满足这个条件才匹配后面的字符。(?:(?!<ex>|<\/ex>).)*
它执行上述步骤零次或多次,直到检测到字符串<ex>
或。</ex>
一旦找到这两个字符串中的任何一个,它就会突然停止匹配以下字符。(?:(?!<ex>|<\/ex>).)*<\/ex>
也匹配以下</ex>
字符串。这一切都被纳入了前瞻中。&(?=(?:(?!<ex>|<\/ex>).)*<\/ex>)
&
最后,只有后面跟着满足上述条件的字符时,它才匹配该字符。即,&
后面必须跟任何不属于的字符,<ex>
或者后面必须</ex>
跟有结束标记零次或多次</ex>
答案4
如果行中出现不止一次,而不是嵌套,也许这会有所帮助:
#cat plop
>a & b & c <ex> a & b & c </ex> a & b & c <ex> a & b & c </ex> a & b & c
#cat plop |sed -e :1 -e 's@\(<ex>[^(</ex>)]*\)&\(.*</ex>\)@\1+\2@;t1'
>a & b & c <ex> a + b + c </ex> a & b & c <ex> a + b + c </ex> a & b & c