可以访问最长的匹配(从头开始),无需替换子字符串

时间:2015-07-09 00:12:40

标签: regex bash sed

我想知道是否可以使用sed来匹配最长的字符串(从头开始)不包含子字符串,以后可以使用sed的正则表达式替换变量\n来访问任何匹配。 / p>

关于以下代码段

echo "blabla/a/b/dee/per" | sed -r -e 's:([^/a]*):\1:g'

我正在尝试打印包含*指示的任何符号的最长匹配,但不包括子串/a以上述代码段打印出来的方式

blabla

关于(/a删除/替换)

echo "blabla/b/b/dee/per" | sed -r -e 's:([^/a]*):\1:g'

我期待

blabla/b/b/dee/per

由于子串/a导致的输出不可用,因此最长的匹配导致字符串结束。我被困在描述子串/a

注意: [^/a]只是占位符来描述问题。它需要用正确的子字符串描述替换imo。 是否有可能以某种方式使用sed?

提前谢谢

编辑: John1024的第三个答案完成了这个问题。现在使用以下代码段:

 sed -r -e 's:(/a|$):\x00:;s:^(.*)\x00(.*):\1:g'

编辑,以完成我的原始任务,将值添加到包含不同前缀的pathes中,其中包含由其他字符包围的子字符串,最后出现了

 $ echo -ne "blabla/a/b/dee/per\nblabla/b/dee/per" | \
   sed -r -e 's:(.*)/a/b:\1\x00:;s:(.*)/b:\1\x01:;s:^(.*)\x00(.*):\1/foo/a/b\2:g;s:^(.*)\x01(.*):\1/foo/b\2:g'
 blabla/foo/a/b/dee/per
 blabla/foo/b/dee/per

首先用/a/b/b替换前缀pathes \x00\x01,分别通过\n访问sed组,即前缀和后缀pathes如下所述。

注:此处使用的其他技巧可避免(.*)/b匹配(.*)/a/b 也就是首先替换最长的路径前缀。 再次感谢@ John1024

1 个答案:

答案 0 :(得分:2)

从开头到第一次出现/a(问题的第二个版本)

查找字符串
$ echo "blabla/a/b/dee/per" | sed 's|/a.*||'
blabla

$ echo "blabla/b/b/dee/per" | sed 's|/a.*||'
blabla/b/b/dee/per

查找不包含/a的最长字符串(原始问题)

这个问题与awk更自然匹配:

$ echo "blabla/a/b/dee/per" | awk -v RS='/a' 'length($0)>max{longest=$0; max=length(longest);} END{print longest;}'
/b/dee/per

$ echo "blabla/b/b/dee/per" | awk -v RS='/a' 'length($0)>max{longest=$0; max=length(longest);} END{print longest;}'
blabla/b/b/dee/per

如何运作

  • -v RS='/a'

    这会将记录分隔符设置为/a。这会在每次出现/a

  • 时对输入进行划分
  • length($0)>max{longest=$0; max=length(longest);}

    如果当前记录$0长于上一个最长记录,请使用新记录更新longestmax

  • END{print longest;}

    当我们到达输入的末尾时,打印出我们看到的longest记录。

从sed组中的第一个/a开始捕获字符串(第3版问题)

$ echo "blabla/a/b/dee/per" | sed -r 's!(/a|$)!\x00!; s|^(.*)\x00.*|I found "\1".|'
I found "blabla".

$ echo "blabla/b/b/dee/per" | sed -r 's!(/a|$)!\x00!; s|^(.*)\x00.*|I found "\1".|'
I found "blabla/b/b/dee/per".

工作原理:

  • s!(/a|$)!\x00!

    这会将第一次出现的/a替换为NUL字符\x00。如果未找到/a,则NUL字符将放置在字符串的末尾(由$表示为正则表达式)。 (选择NUL字符是因为它永远不能保存在bash变量中,因此极不可能存在于输入字符串中。)

  • s|^(.*)\x00.*|I found "\1".|

    这将第1组的所有字符保存到第一个/a以前的位置。我们可以随意使用\1

如上所述,这需要一个sed,例如GNU sed,它支持NUL字符,十六进制00.如果你的sed不支持NUL,那么将\x00替换为一些赢得' t在您的输入字符串中,但您的sed确实支持。 \x01可能是一个不错的第二选择。