0

Basically I want to find foobar on uncommented lines like:

// foobar      # do not match me
 foobar        # match me
 otherfoobar   # do not match me

To match the commented lines I use this: ^(\s*//\s*)\bfoobar\b.*$

How do I match the uncommented lines?

NOTE:

To avoid unnecessary efforts, please restrict the answers to '^...$'. This has to be done purely inside a string sent to perl for matching.

Also foobar must be matched whole as in \bfoobar\b

Finally \bfoobar\b should not be preceeded with anything but whitespace or the comment signature.

  • perhaps just use next if $_ =~ m!^//!; ? – Jeff Schaller Jun 16 at 13:07
  • It is clear that an un-comment line is any that do not start with ^\s*//\s*. Use if not m,^\s*//,. However, it is not clear which un-commented lines you want to match: ones that start with foobar? The ones that contain foobar as a separate word? Could you clarify? – Isaac Jun 16 at 17:03
  • yes. keep in mind that we are looking for uncommented lines for foobar – conanDrum Jun 16 at 17:05
  • To avoid unnecessary efforts, please restrict the answers to '^...$'. This has to be done purely inside a string sent to perl for matching. – conanDrum Jun 16 at 17:10
  • added some notes in question to clarify – conanDrum Jun 16 at 17:14
1

I think the issue of negation should not be over complicated.

e.g. say I am looking to reject these lines:

"^(\s*//\s*).*(\bfoobar\b).*$"

ie. having the comment signature '//' anywhere in whitespace, at the beginning, followed by anything which includes 'foobar' as a whole word (included brackets for clarity).

to negate this we do:

"^(?!\s*//\s*).*(\bfoobar\b).*$"

we just replace (\s*//\s*) with (?!\s*//\s*)

This disregards anything having the comment signature '//' anywhere in whitespace, at the beginning, followed by our pattern.

Results:

  // foobar will not be matched
  // whatever foobar will not be matched
  foobar will be matched
  whatever foobar will be matched
  whateverfoobar will not be matched

NOTE: you can further finely tune by changing the .* before (\bfoobar... and you are set.

e.g. I can do "^(?!\s*//\s*)\s*(\bfoobar\b).*$"

  foobar will be matched
  whatever foobar will **NOT** be matched

WARNING: if you ever replace 'foobar' with some arbitrary string like '${foobar}' and you try the above, it will fail. the reason is because your normal 'foobar' was made up of just word characters and now (\bfoobar\b) will not match it. In this case, \b must be removed.

1

If you're using Perl (the language) and not some tool using Perl-compatible regexes, there's no reason to restrict yourself to just one regex.

Something like this would match just the uncommented line:

$ perl -ne 'print if not m,^\s*//, and /\bfoobar\b/' < file.txt 
 foobar        # match me

Even with other utilities, or non-Perl regexes, it might be easiest to just use multiple regexes:

$ < file.txt grep -ve '//' | grep '\<foobar\>'
 foobar        # match me

If, instead, you are restricted to a single Perl regex, then this should work:

grep -P '^\s*+(?!//).*\bfoobar\b.*$' file.txt

The \s*+ is a "possessive" expression, which matches all leading whitespace, and doesn't let go of them. Then (?!//) checks that whatever is after the leading whitespace isn't the comment marker, and finally we look for foobar within word breaks anywhere on the line.

(If the whitespace was matched without the possessive qualifier, the regex engine could back off from the leading whitespace, and check for the comment marker in the wrong place, leading to commented lines being matched.)

Test data:

$ cat file.txt
 // foobar        # do not match
 foobar           # 1st match
otherfoobar       # do not match
something foobar  # 2nd and final match
$ grep -P '^\s*+(?!//).*\bfoobar\b.*$' file.txt
 foobar           # 1st match
something foobar  # 2nd and final match
  • thanks but this has to be done inside '^...$' – conanDrum Jun 16 at 17:07
  • @conanDrum, allright, see edit – ilkkachu Jun 16 at 19:38
1

A foobar not found to the right of a // could be expressed as:

^(?:(?!//).)*\bfoobar\b

That is a sequence of 0 or more (*) characters (.) which each are not at the start of a // sequence ((?!//)), followed by a foobar delimited by word boundaries.

  • 1
    Simple, and works otherwise, but detects the comment marker even after non-whitespace (i.e. it doesn't match xx // foobar or such). That's probably a bit of a corner case but the description was that there could only be whitespace before the comment marker. – ilkkachu Jun 17 at 5:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.