假设我有类似以下的文本:
敏捷的棕色狐狸在 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\}/&####/"
注入####
首先四位数字。(警告:这将更改为65536
。6553####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#### 中跳跃。
然后
快速变黄。