Reputation: 644
I'm trying to make a one-liner script that prints when github
is not behind golang
.
For example, java is a language used in github
should match, but golang is a language used in github
shouldn't match.
I've tried the expression /(?<!golang).*github/
, but it doesn't work.
echo "golang is a language used in github" |
perl -nle'print /(?<!golang).*github/ ? "match" : "no match"'
This prints match
instead of no match
.
How can I do that using "negative look-behind" in Perl?
(Using Perl v5.28.1)
Upvotes: 0
Views: 420
Reputation: 705
Your expression matches all strings with the word "github
" in them. Let's see why:
/(?<!golang).*github/
will match as long as Perl can adjust the .*
to match just enough characters to not run into a situation where it's immediately preceded by golang
. Regexes being greedy, the .*
will match as much as it can while still having the rest of the pattern match.
So if your string is
golang is a language used in github
The regex can match by assigning string to different parts:
(?<!golang)
matches at the beginning of the string.*
gets "golang is a language used in
"github
gets "github
"A potentially costly way to accomplish what you wanted is:
/^(?:(?!golang).)*github/
It works by making sure none of the characters preceding "github
" begin the sequence "golang
".
So
echo "java is a language used in github" | perl -ne 'print q!Not golang: !, /^(?:(?!golang).)*github/ ? q!true! : q!false!'
will print out Not golang: true
while
echo "golang is a language used in github" | perl -ne 'print q!Not golang: !, /^(?:(?!golang).)*github/ ? q!true! : q!false!'
will print out Not golang: false
.
Another (less obfuscated) way is to do two consecutive tests:
/^(.*)github/ and $1 !~ /golang/
If you're doing tens or hundreds of thousands of lines, maybe test both ways to find which is faster?
Upvotes: 3
Reputation: 425238
Just use a negative look ahead anchored to start:
^(?!.*golang).*github
Upvotes: -1