How to negate perl regex with lookbehind?

Viewed 100

I have this text (file.txt) to inspect:

_abcd
_efgh
#, _1

Now I want to match only words with underscore but that are not preceded with hash #. To mach all, I can do

$perl -nle 'print $1 if /(_\w+)/' file.txt

But I dont want to match the hash, so I will try the lookbehind:

$ perl -nle 'print $1 if /(?<!#.+)(_\w+)/' file.txt

Variable length lookbehind not implemented in regex m/(?<!#.+)(_\w+)/ at -e line 1.
  1. How to implement variable length lookbehind in perl?

For the second, I will try to do lookahead:

$ perl -nle 'print $1 if /(?!#.+)(_\w+)/' file.txt

which will again match all, including the # line, which I do not want.

  1. How to match all, except the # line (in other words, how to negate regex)?
2 Answers

You may use

/#.+(*SKIP)(*F)|_\w+/

Or, to match _ at the word boundary:

/#.+(*SKIP)(*F)|\b_\w+/

The pattern matches

  • #.+(*SKIP)(*F) - # and any 1 or more chars other than line break chars as many as possible, and then the match is skipped, omitted, discarded and the next match is searched for from the place where the match was skipped
  • | - or
  • _\w+ - a _ and then any 1 or more word chars.

The following will do:

/^[^#]*(_\w+)/
Related