我有两个模式START
和END
,并希望用这些模式之间的下划线替换每个空间。
例
Lorem ipsum dolor START sit amet, consectetur END adipiscing elit.
应该转变为
Lorem ipsum dolor START_sit_amet,_consectetur_END adipiscing elit.
我知道正则表达式用下划线替换每个空格
sed 's/ /_/g'
我也知道如何匹配两种模式之间的部分
sed 's/.*START\(.*\)END.*/\1/g'
但我不知道如何将这两件事结合起来。
作为替代方案,您可以使用Perl:
perl -pe 's/(START.*?END)/$1=~s#\s#_#gr/ge'
(START.*?END)
模式匹配START
和END
之间的子串,同时将其捕获到组1中,然后s#\s#_#gr
用组中的\s
替换每个单个空格(_
)。
或者,如果您使用不支持r
选项的Perl:
perl -pe 's/(?:START|\G(?!^))(?:(?!END).)*?\K\s/_/g'
参见online demo和second regex demo online。
(?:START|\G(?!^))(?:(?!END).)*?\K\s
比赛
(?:START|\G(?!^))
- START
子串或上一次成功比赛结束(与\G(?!^)
)(?:(?!END).)*?
- 任何字符,但换行符,而不是启动END
子字符串,尽可能少\K
- 匹配重置运算符,丢弃先前匹配的文本\s
- 一个空白字符。你可以使用这个awk
来完成你的工作:
awk -v ts='START ' -v te='END ' '{
while (n = index($0, ts)) {
m = index($0, te)
if (m > n) {
s = substr($0, n, m-n)
gsub(/[[:blank:]]+/, "_", s)
$0 = substr($0, 1, n-1) s substr($0, m)
}
}
} 1' file
Lorem ipsum dolor START_sit_amet,_consectetur_END adipiscing elit.
使用GNU awk:
awk -v RS='(START|END)' 'RT=="END"{gsub(" ","_")}{printf "%s%s",$0,RT}' file
这依赖于记录分隔符RS
设置为START
或END
。
如果到达END
标记,则更新记录以使用函数gsub()
替换带下划线的空格。
最后一个语句打印整个记录,包括记录终止符RT
(与RS
匹配)。
请注意,此解决方案允许START
和END
跨越不同的行(并且必须在同一行上)。