John Westlund John Westlund - 5 months ago 11
Perl Question

perl regex negative set matching string in negative lookahead

I'm trying to match any set of characters (inside square brackets) other then square brackets (

[^\[\]]+
) -- unless the last part of the string of characters matches
-notme
.

perl -sp -e 'if (/\[[^\[\]]+?(?!-notme)\]$/../^no/)
{ print "#"; s/^yes/$VAR/; }' -- -VAR="CHANGED" /tmp/input


My input file looks like this:

-bash-4.2# cat /tmp/input
[test-ing]
yes
yes
no
maybe

[test-ing-notme]
yes
yes
no
maybe


But my output looks like:

#[test-ing]
#CHANGED
#CHANGED
#no
maybe

#[test-ing-notme]
#CHANGED
#CHANGED
#no
maybe


My speculation is that the negative set is matching what my negative lookahead should be not matching -- hence my attempt with lazy matching of the negative set, but the result is the same as if it were a greedy match.

My expectation would be that the output would look like:

#[test-ing]
#CHANGED
#CHANGED
#no
maybe

[test-ing-notme]
yes
yes
no
maybe

Answer

You should change the pattern: /\[[^\[\]]+?(?!-notme)\]$/ to

/\[[^][]++(?<!-notme)]$/
#       ^ ^-------------- a negative loobehind before the closing bracket
#       '---------------- a possessive quantifier to prevent backtracking

In this way, you are sure that "-notme" isn't tested at useless positions in the string.