sed-在模式之间应用替换

时间:2018-09-12 10:37:05

标签: regex sed substitution

我有两种模式STARTEND,想用这些模式之间的下划线替换每个空格。

示例

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'

但是我不知道如何将这两件事结合起来。

3 个答案:

答案 0 :(得分:2)

您也可以使用Perl:

perl -pe 's/(START.*?END)/$1=~s#\s#_#gr/ge'

(START.*?END)模式匹配STARTEND之间的子字符串,同时将其捕获到组1中,然后s#\s#_#gr将每个单个空格(\s)替换为_在该组的内容中。

或者,如果您使用的Perl不支持r选项:

perl -pe 's/(?:START|\G(?!^))(?:(?!END).)*?\K\s/_/g'

请参见online demosecond regex demo online

(?:START|\G(?!^))(?:(?!END).)*?\K\s匹配

  • (?:START|\G(?!^))-START子字符串或上一个成功匹配的结尾(与\G(?!^)一起结束)
  • (?:(?!END).)*?-除换行符以外的任何字符,不以END子字符串开头,应尽可能少
  • \K-匹配重置运算符,丢弃先前匹配的文本
  • \s-空格字符。

答案 1 :(得分:1)

您可以使用此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.

答案 2 :(得分:1)

使用GNU awk:

import json
chunk_size = 1024
with open('file.txt', 'rb+') as f:
    f.seek(-chunk_size, 2)
    buffer = ''
    while True:
        fragments = f.read(chunk_size).decode().split('{')
        f.seek(-chunk_size * 2, 1)
        i = len(fragments)
        for fragment in fragments[:0:-1]:
            i -= 1
            buffer = '{%s%s' % (fragment, buffer)
            try:
                json.loads(buffer)
                break
            except ValueError:
                pass
        else:
            buffer = fragments[0] + buffer
            continue
        break
    next_fragment = fragments[i - 1]
    # if we don't have a comma in the preceding fragment and it is already the first
    # fragment, we need to read backwards a little more
    if i == 1 and ',' not in fragments[0]:
        f.seek(-2, 1)
        next_fragment = f.read(2).decode() + next_fragment
    buffer = next_fragment[next_fragment.rindex(','):] + buffer
    f.seek(-len(buffer.encode()), 2)
    f.truncate()

这取决于将记录分隔符awk -v RS='(START|END)' 'RT=="END"{gsub(" ","_")}{printf "%s%s",$0,RT}' file 设置为RSSTART

如果到达END标记,则会使用功能END更新记录以用下划线替换空格。

最后一条语句打印整个记录,包括记录终止符gsub()(与RT匹配)。

请注意,此解决方案允许RSSTART跨越不同的行(并且必须在同一行)。