Heaven has asked for the wisdom of the Perl Monks concerning the following question:

I would like to get suggestions as how to perform the following using pattern matching regex:
Input :
"Exception : CEX
Exception : TEX
abc def ljj"
Regex for : I want to get all lines with "Exception" followed by anything except CEX .
Required Output : Exception TEX .

Replies are listed 'Best First'.
Re: Match with line without a word
by moritz (Cardinal) on Aug 07, 2009 at 07:39 UTC
    It's easiest to do it in two regexes: print the line if it matches Exception and not matches Exception : CEX.
Re: Match with line without a word
by Heaven (Initiate) on Aug 07, 2009 at 07:42 UTC
    Yes , I already worked it out with 2 regex. I wanted to know if there is a more efficient way of doing it with one regex .
      There is a way with one regex, but I don't think it will be much more efficient. Untested: /Exception : (?!CEX)/.

      See perlre for details on the look-ahead group

        use strict; use warnings; use Benchmark; my @strings = qw(exception:tex exception:mex asdf); Benchmark::cmpthese( -5, { 'one' => sub { my @filtered = grep { /exception:(?!tex)/} @strings +; }, 'two' => sub { my @filtered = grep { /exception/ && !/tex/ } @stri +ngs; }, }); __END__ Rate one two one 175458/s -- -15% two 207611/s 18% --

        update: The filter expressions are different. The second one does not care whether tex is before of after exception and doesn't require a ':' after 'exception'. I have stumbled on a patch of my ignorance trying to make the second match the same strings as the first. The best I have so far is:

        use strict; use warnings; use Benchmark; my @strings = qw(exception:tex exception:mex asdf tex:exception:mex); Benchmark::cmpthese( -5, { 'one' => sub { my @filtered = grep { /exception:(?!tex)/} @strings +; }, 'two' => sub { my @filtered = grep { /exception/ && !/tex/ } @stri +ngs; }, 'three' => sub { my @filtered = grep { pos = 0; /exception:/g && ! +/\Gtex/ } @strings; }, }); __END__ Rate three one two three 99554/s -- -18% -38% one 121692/s 22% -- -24% two 161067/s 62% 32% --

        update: see also strange behavior of grep with global match [resolved]. Adding "pos = 0" is necessary to clear pos between iterations but it would not be necessary if there were only a single iteration. This makes it difficult to compare the efficiency of "/exception/g && !/\Gtex/".

      There are a number of ways to do this. Easy way is with cascading "greps", like in my first example. Regex is wonderful at "or" but the "and" kind of thing can be complex in the syntax.

      I would suggest one of the below formulations. Tweak to suit your needs.

      oops, my brain is really out to lunch today...sorry.see update

      #!/usr/bin/perl -w use strict; my @input = ("Exception : CEX", "Exception : TEX", "abc def ljj"); print grep{/TEX/} grep{/^\s*Exception/}@input; print "\n"; print grep{/Exception/ && /TEX/}@input; print "\n"; print grep{/^\s*Exception.*? TEX/}@input; __END__ prints: Exception : TEX Exception : TEX Exception : TEX
      #!/usr/bin/perl -w use strict; my @input = ("Exception : CEX", "Exception : TEX", "abc def ljj"); print grep{!/CEX/}grep{/^\s*Exception/}@input; print "\n"; print grep{/Exception/ && !/CEX/}@input; print "\n"; __END__ prints: Exception : TEX Exception : TEX
      I wouldn't get overly concerned about performance unless this code is going to be executed lots of times. Clarity should be the first priority.
        Thanks a lot . I think this grep usage would do good , than nested regex .