匹配第一个模式后,第二个模式

时间:2015-05-26 12:40:19

标签: regex perl sed grep tcl

是否有任何grep / sed选项允许我在匹配其他模式后匹配模式?例如:输入文件(foo s是以0开头的变量模式,混合了前面带有#的随机数字:

0foo1  
0foo2  
0foo3  
\#89888  
0foo4  
0foo5  
\#98980  
 0foo6

因此,一旦我尝试搜索变量模式(例如foo2),我还想匹配此模式行号的另一个模式(例如#number),在本例中为{ {1}}。

因此变量#89888的输出必须是:

foo2

对于变量foo2 #89888

foo5

foo5 #98980 由每个字符组成,包括可被视为元字符的字符。

我使用tcl尝试了一个基本的正则表达式匹配脚本,它首先搜索foo,然后搜索下一个立即foo*,但由于我正在处理一个非常大的文件,所以需要几天时间完。任何帮助表示赞赏。

7 个答案:

答案 0 :(得分:2)

Perl one-liner用于覆盖整个文件,并匹配您寻找的模式的任何换行符:

perl -000  -nle 'm{(foo2).*(\#89888)}s and print join " ",$1,$2' file

-000开关启用" slurp"告知Perl不将文件拆分成块的模式,而是将其视为一个大字符串。 s修饰符可让.匹配任何字符,包括换行符。

答案 1 :(得分:0)

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;

my ( %matches, $recent_foo );

while(<DATA>)
{
   chomp;
   ( $matches{$recent_foo} ) = $1 if m/(\\#\d+)/;
   ( $recent_foo ) = $1 if m/(0foo\d+)/;
}

print Dumper( \%matches );

__DATA__
0foo1  
0foo2  
0foo3  
\#89888  
0foo4  
0foo5  
\#98980  
 0foo6

 ./perl 
$VAR1 = {
          '0foo5' => '\\#98980',
          '0foo3' => '\\#89888'
        };

答案 2 :(得分:0)

如果你想要的是0foo10foo20foo3都具有相同的值,则以下操作:

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;

my ( %matches, @recent_foo );

while(<DATA>)
{
   chomp;
   if (/^\\#/)
   {
     @matches{@recent_foo} = ($') x @recent_foo;
     undef @recent_foo;
   }
   elsif (/^0/)
   {
     push @recent_foo, $';
   }
}

print Dumper( \%matches );

__DATA__
0foo1
0foo2
0foo3
\#89888
0foo4
0foo5
\#98980
0foo6

给出:

$VAR1 = {
          'foo2' => '89888',
          'foo1' => '89888',
          'foo5' => '98980',
          'foo3' => '89888',
          'foo4' => '98980'
        };

答案 3 :(得分:0)

Var='foo2'
sed "#n
/${Var}/,/#[0-9]\{1,\}/ {
   H
   /#[0-9]\{1,\}/ !d
   s/.*//;x
   s/.//;s/\n.*\\n/ /p
   q
   }" YourFile

不清楚请求。它首先出现你的模式 foo2 直到第一个 #number ,删除之间的行并打印出1行而不是退出(没有其他提取

答案 4 :(得分:0)

Tcl解决方案。该过程运行时间超过3微秒,因此您需要非常大型数据文件才能运行数天。如果多个令牌匹配,则使用第一个匹配(很容易重写该过程以返回所有匹配)。

set data {
0foo1  
0foo2  
0foo3  
\#89888  
0foo4  
0foo5  
\#98980  
 0foo6
}

proc find {data pattern} {
    set idx [lsearch -regexp $data $pattern]
    if {$idx >= 0} {
        lrange $data $idx $idx+1
    }
}

find $data 0foo3
# -> 0foo3 #89888
find $data 0f.*5
# -> 0foo5 #98980

文档:iflrangelsearchprocset

答案 5 :(得分:0)

SED

 <div class="navbar navbar-default">
    <div class="navbar-inner">
        <div class="container">
            <div class="navbar-header">
                <button type="button"
                        class="navbar-toggle"
                        data-toggle="collapse"
                        data-target="#myCollapseGuy">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a id="siteTitle" class="navbar-brand" href="/">Joseph Anthony King</a>
            </div>
            <div class="navbar-collapse collapse" id="myCollapseGuy">
            <ul class="nav navbar-nav pull-right">
                <li class="dropdown">
                    <a href="/">Home</a>
                </li>
                <li class="dropdown">
                    <a href="/Resume">Resume</a>
                </li>
                <li class="dropdown">
                    <a href="/Downloads">Downloads</a>
                </li>
                <li class="dropdown">
                    <a href="https://joe-king-sample-app.herokuapp.com/" target="_blank">
                        Sample App
                    </a>
                </li>
            </ul>
            </div>
        </div>
    </div>
</div>
  • 第一个sed打印第一个模式和第二个模式之间的所有行,删除可选的前导空格和前导sed -n '/foo2/,/#[0-9]\+/ {s/^[[:space:]]*[0\\]//; p}' file | sed -n '1p; $p' | paste -s 0
  • 第二个sed仅提取第一行和最后一行。
  • 粘贴命令将2行打印为一行,用制表符分隔。

AWK

\

TCL

awk -v p1=foo5 '
    $0 ~ p1 {found = 1} 
    found && /#[0-9]+/ { sub(/^\\\/, ""); print p1, $0; exit }
' file

然后

lassign $argv filename pattern1
set found false
set fid [open $filename r]
while {[gets $fid line] != -1} {
    if {[string match "*$pattern1*" $line]} {
        set found true
    }
    if {$found && [regexp {#\d+} $line number]} {
        puts "$pattern1 $number"
        break
    }
}
close $fid

答案 6 :(得分:0)

这是你想要的吗?

$ awk -v tgt="foo2" 'index($0,tgt){f=1} f&&/#[0-9]/{print tgt, $0; exit}' file
foo2 \#89888

$ awk -v tgt="foo5" 'index($0,tgt){f=1} f&&/#[0-9]/{print tgt, $0; exit}' file
foo5 \#98980

我在上面使用index(),因为它搜索字符串而不是regexp,所以不必关心foo中的RE元字符是什么 - 它们都只是字符串中的文字字符。

如果你想在特定的foo之后找到一个特定的数字或foo2之后的第一个数字,或者你想要搜索特定的foo值或者所有&#34; foo& #34; s或......