【问题标题】:sed: How to substitute within a match?sed:如何在比赛中替换?
【发布时间】:2016-01-05 09:58:03
【问题描述】:

使用regexr,我写了表达式/[\.!?] [A-Z]/g,使用3个假设来匹配句子:

  1. 句子以标点符号结尾:[.,!?](我不知道如何匹配双标点符号或组合...)
  2. 标点符号后面总是有一个或多个空格。
  3. 下一句以大写字母开头。 (99% 的情况是正确的,除了小写名词,例如 iDevices)

使用sed,我想获取这些匹配项,并将空格替换为\n 字符。我可以做一个匹配后的 $' 和一个匹配前的 $`,但是如何在匹配中替换?

如果有更好的方法将文本分成每行一个句子,我愿意接受替代方案。

无 bashisms:适用于 Linux、OS X 和 BSD

输入:

Vivamus fermentum semper porta。 Nunc diam velit,脂肪粒 tristique vitae,sagittis vel odio。 Maecenas convallis ullamcorper 奥特莱斯。 Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit,id fringilla sem nunc vel mi。

输出:

Vivamus fermentum semper porta.
Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio.
Maecenas convallis ullamcorper ultricies.
Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi.

【问题讨论】:

    标签: regex sed posix sh


    【解决方案1】:

    你可以使用这个替换:

    sed 's/\([.!?][.!?]*\)  *\([A-Z]\)/\1\n\2/g;' file
    

    \(...\) 分隔捕获组,\1 是对捕获内容的引用。

    OSX 版本的 sed 不会将 \n 解释为换行符,您必须使用序列 \1'$'\n\\2 作为替换字符串。

    一种更 POSIX 的方式包括编写:

    sed 's/\([.!?][.!?]*\)  *\([A-Z]\)/\1\
    \2/g;' file
    

    @cliffordheath 建议使用转义换行符。

    请注意,点不需要在字符类中转义。

    【讨论】:

    • 在 OS X 上:sed 's/\([.!?][.!?]*\) *\([A-Z]\)/\1\'$'\n\\2/g(由于某种原因,我不得不转义 \n\2),但您的答案是迄今为止最好的答案,因为它还考虑了大写字母。
    • 你的案子里根本不需要处理信件
    【解决方案2】:

    您需要使用带有 \( 和 \) 的捕获组来重新插入标点符号和首字母。此示例允许以下句子以任何字母数字开头(但至少需要一个空格以避免混淆十进制数字):

    $ sed -e 's/\([.!?]\)  *\([[:alnum:]]\)/\1\
    \2/g'
    foo.   bat!  baz?  foo,  bar.
    foo.
    bat!
    baz?
    foo,  bar.
    

    我希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 2019-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多