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