sed:删除字符串之间的文本直到第一次出现另一个字符串

sed:删除字符串之间的文本直到第一次出现另一个字符串

假设我有类似以下的文本:

敏捷的棕色狐狸在 2012 年和 2013 年跳跃

我希望删除“fox”中的部分,包括四个数字,但只删除第一次出现的部分,因此最终得到:

2013 年的快速棕色

类似于这样的……:

echo "敏捷的棕色狐狸在 2012 年和 2013 年跳跃" \
   | sed “s/fox.*\([0-9]\{4\}\)//g”

...带给我:

快速棕色

因此它删除了所有内容,包括最后出现的四个数字。

有任何想法吗?

答案1

使用的 POSIX 正则表达式sed(“基本”版和“扩展”版)不支持非贪婪匹配。(尽管有一些解决方法,例如使用[^0-9]*代替.*,但如果输入变化很大,它们就会变得不可靠。)

?您可以在 Perl 中使用非贪婪量词来实现所需的目的:

echo "The quick brown fox jumps in 2012 and 2013" \
   | perl -pe 's/fox.*?([0-9]{4})//g'

您可能还希望删除多余的空格。

答案2

假设你想使用仅有的sed 并且希望匹配的结束是第一组数字,而不关心数字后面的单词是什么,这样做有效:

echo "敏捷的棕色狐狸在 2012 年和 2013 年跳跃" \
   | sed “s/fox[^0-9][^0-9]*[0-9][0-9]* //”

该模式的工作原理是匹配fox,后跟一个或多个非数字[^0-9][^0-9]*,后跟一个或多个数字[0-9][0-9]*。此模式适用于任意数量的数字,而不仅仅是 4 位。如果要匹配精确的 4 位数字,请将其更改为:

echo "敏捷的棕色狐狸在 2012 年和 2013 年跳跃" \
   | sed “s/fox[^0-9]*\([0-9]\{4\}\) //”

答案3

你没有指定确切地你的需求是什么。你可能需要多步骤的过程。选择一个你知道不会出现在输入中的字符串(例如:)####

echo “这只敏捷的棕色狐狸在 2012 年和 2013 年跳过了 42 只懒狗。”\
  | sed \
        -e "s/[0-9]\{4\}/&####/" \
        -e “s/fox.####//” \
        -e “s/####//”

(为了便于阅读,命令过度折叠。)之后的-e "s/[0-9]\{4\}/&####/"注入####首先四位数字。(警告:这将更改为655366553####6
-e "s/fox.*####//"影响包含fox和的行####- 即包含至少一个四位数字的行 - 然后从到fox删除首先四位数字。
-e "s/####//"当然,会清除####包含四位数字但不包含的行中遗留的任何字符串fox

如果数字后面有一个空格,则删除该空格,

echo “这只敏捷的棕色狐狸在 2012 年和 2013 年跳过了 42 只懒狗。”\
  | sed \
        -e "s/[0-9]\{4\}/&####/" \
        -e "s/fox.####//" \
        -e “s/fox.####//” \
        -e “s/####//”

警告:您可以添加g到所有s命令,但是,由于这仍然使用.*,这是问题的根源,它仍然无法处理

One fox jumps in 2012 and 2013, another fox will jump in 2014 and 2015.

你可能想要的方式。当然,你想要添加g到,"s/[0-9]\{4\}/&####/"因为它会在之后####注入每一个四位数字,完全违背了要点。然后最终会像(删除了无贡献字符的原始命令)"s/fox.*####//"一样运行;即,它将改变"s/fox.*[0-9]\{4\}//"

这只敏捷的棕色狐狸在 2012 年和 2013 年跳跃。

敏捷的棕色狐狸在 2012#### 和 2013#### 中跳跃。

然后

快速变黄。

相关内容