我们真的可以没有懒惰的量词吗?

时间:2011-10-04 00:46:57

标签: regex sed awk grep

很多人说我们可以在正则表达式中没有懒惰的量词,但我遇到了一个问题,没有它我无法解决(我在这里使用sed)。

我想要处理的字符串由以字速率分隔的子字符串组成,例如:

anfhwe9.<<76xnf9247 rate 7dh3_29snpq+074j rate 48jdhsn3gus8 rate

我想用3个破折号(---)替换那些子串(除了' rate '之外);结果应该是:

---rate---rate---rate

根据我的理解(我不知道Perl),可以使用惰性量词轻松完成。在vim中也有懒惰的量词;我是用这个命令做的

:s/.\{-}rate/---rate/g

\{-}告诉vim尽可能少匹配。

但是,vim是一个文本编辑器,我需要在许多机器上运行脚本,其中一些机器没有安装Perl。如果您可以告诉正则表达式与.*[^(rate)]rate之类的原子分组不匹配但是不起作用,也可以解决它。

任何想法如何使用POSIX正则表达式实现这一点,还是不可能?

6 个答案:

答案 0 :(得分:3)

在这种情况下,我会使用split():

perl -n -e 'print join ("rate", ("---") x split /rate/)' [input-file]

答案 1 :(得分:2)

如果不使用延迟量词或负向前瞻(POSIX都不支持),这并不容易,但这似乎有效。

([^r]*((r($|[^a]|a([^t]|$)|at([^e]|$))))?)+rate

我模糊地回忆起POSIX角色类有点不耐烦。如果它们不符合POSIX标准,您可能需要更改该正则表达式中的字符类。

答案 2 :(得分:2)

是否有任何字符可以保证不在输入中?例如,如果'!' 不能发生,您可以转换输入以替换该唯一字符,然后对转换后的输入执行全局替换:

sed 's/ rate /!/g' < input | sed -e 's/[^!]*/---/g' -e 's/!/rate/g'

另一种方法是以类似的方式使用awk的split命令 上面的perl建议,假设awk比perl更可靠。

awk '
{   ans="---"
    n=split($0, x, / rate /);
    while ( n-- ) { ans = ans "rate---";}
    print ans
}'

答案 3 :(得分:1)

您不关心子串的内容这一事实开辟了许多选择。例如,添加Bob Lied的建议 - 即使'!'可以在输入中出现,您可以将其更改为其他内容:

sed -e 's/!/./g' -e 's/rate/!/g' -e 's/[^!]\+/---/g' -e 's/!/rate/g' <input >output

答案 4 :(得分:0)

使用 awk

awk -Frate '{ 
  for (i = 0; ++i <= NF;) 
    $i = (i == 1 || i == NF) && $i == x ? x : "---" 
  }1' OFS=rate infile   

答案 5 :(得分:0)

或者,awk 'BEGIN {OFS=FS="rate"} {for (i=1; i<=NF-1; i++) {$i = "---"}; print}'