太长了;博士

太长了;博士

本质上,我试图获取两个字符串之间的内容,但使用相同的字符重复 N 次,如下所示:

===
This is a test
===

====
Another test
====

==
Last test
==

当然以上只是一个例子。这是我的尝试和结果:

sed -u '/==/!d;s//&\n/;s/.*\n//;:a;/==/bb;$!{n;ba};:b;s//\n&/;P;D' testfile

=
This is a test

=




Another test






Last test


如果我只使用上述之一testfile


Last test


这将给出想要的结果(尽管添加了太多换行符,但对于本示例来说这很好)。

仅当这些重复字符只有一个实例或者是一对包含内容的唯一字符串时,上述方法才有效......

如何使用相同数量的重复字符获取两个字符串之间的内容?我更喜欢使用grep,sedawk来实现此目的。

答案1

我们使用awk使用触发器逻辑从打开状态切换到关闭状态的实用程序,如下所示:

$ awk -v str="==" '
      $0""==str{f=!f;next};f
' testfile
Last test

使用Posixlysed我们可以实现触发器逻辑的构造:

sed -ne '
  /^==$/{
    x;        # access state info from hold
    s/^$/0/;  # initialize state
    y/01/10/; # toggle state
    x;        # save state in hold
    d;        # next
  }
  G;/\n1/P
' testfile

使用 GNU 版本的流编辑器sed在其扩展模式下-E

$ sed -Ee '
    $!N; /^(\S)\1+\n/!D
    :loop
        $d;N
        s/^(.*)\n(.*)\n\1$/\2/;t
    bloop
' testfile
This is a test
Another test
Last test

笔记:-

  • 通过N命令保持两行模式空间。
  • 继续拒绝行,直到遇到黄金线(=>其中模式空间的第一部分仅包含单一类型的非空白字符)
  • 一旦找到这样一条线,我们就会循环,直到在路上至少遇到两条线的精确复制品。我们已经找到了第一组。
  • 重复这个过程直到到达 eof。

使用触发器运算...珀尔我们可以这样做,如图所示:

perl -lne 'print if 
 /^(\S)\1+$(?{$a=$_})/ ... $_ eq $a and $_ ne $a;
' testfile

对于要搜索的固定预定字符串甚至更简单,因为这样我们就不必编写正则表达式,而字符串相等性测试就足够了:

$ perl -nlse 'print if
    $_ eq $a ... $_ eq $a and $_ ne $a;
' -- -a=== testfile

$ sed -Ee '
    /^==$/!d
    $!N
    :a
        $d;N
        s/^(.*)\n(.*)\n\1$/\2/;t
    ba
' testfile

答案2

太长了;博士

$ sed '/^==*$/,//{//!p};d' testfile
This is a test
Another test
Last test

乍一看,一个简单的范围可以打印所有对(不需要循环):

$ sed -n '/^=/,//p' testfile
===
This is a test
===
====
Another test
====
==
Last test
==

这会打印以 ( ) 开头的行=和下一个重复的正则表达式 ( //) 之间的每一行。

这可以改进为一条线仅有的包含=/^==*$/.

并删除所有标记:

$ sed -n '/^==*$/,//H;${x;s/\n==*//g;s/^\n//;p}' testfile
This is a test
Another test
Last test

或者,用更简短的形式:

$ sed -n '/^==*$/,//{//d;p}' testfile
This is a test
Another test
Last test

要匹配确切的数量,=请将正则表达式更改为:

$ sed -n '/^==$/,//{//d;p}' testfile
Last test

并且,为了避免该-n选项:

$ sed '/^==$/,//{//!p};d' testfile
Last test

在 awk 中可以这样做:

$ awk 'p==0 && /^==*$/ {p=1;next}
       p==1 && /^==*$/ {p=0}
       p          
      ' testfile

This is a test
Another test
Last test

或者,以一种不太明确的形式:

awk ' /^==*$/ { p = !p ; next}
      p
    ' testfile

答案3

我会用perl

$ perl -0777 -ne 'print $3 while /^((\S)\2+\n)(.*?)^\1/smg' < your-file
This is a test
Another test
Last test

或者pcregrep

$ pcregrep -Mo3 '(?s)^((\S)\2+\n)(.*?)\n?^\1' < your-file
This is a test
Another test
Last test

如果只是返回固定分隔符之间的内容:

$ pcregrep -Mo1 '(?s)^==\n(.*?)\n?^==$' < your-file
Last test

答案4

命令:

awk '{a[++i]=$0}/==/{for(x=NR-1;x<NR;x++)print a[x]}' filename|sed '/^$/d'

输出

This is a test
Another test
Last test

相关内容