Regex to exclude an entire line match if certain characters found

Viewed 295

I'm stuck on the cleanest way to accomplish two bits of regex. Every solution I've come up with so far seems clunky.

Example text
Match:    Choose: blah blah blah 123 for 100'ish characters, this matches

NoMatch:  Choose: blah blah blah 123! for 100'ish characters?, .this potential match fails for the ! ? and .

The first regex (?:^\w+?:)(((?![.!?]).)*)$ needs to:

  • Match a line containing any word followed by a : so long as !?. are not found in the same line (the word: will always be at the beginning of a line)
  • Ideally, match every part of the line from the example EXCEPT Choose:. Matching the whole line is still a win.

The second regex ^(^\w+?:)(?:(?![.!?]).)*$ needs to:

  • Match a line containing any word followed by a : so long as !?. are not found in the same line (the word: will always be at the beginning of a line)
  • Match only Choose:

The regex is in a greasemonkey/tampermonkey script.

3 Answers

Does this do what you want?

(?:^\w+:)((?:(?![!?.]).)*)$

What makes you feel that this is clunky?

    (?: ... )  non-capturing group
    ^          start with
    \w+:       a series of one or more word characters followed by a :
    ( ... )$   capturing group that continues to the end
    (?: ... )* non-capturing group, repeated zero or more times, with
    (?! ... )  negative look-ahead: no following character can be
    [!?.]      either ?, ! or .
    .          followed by any character

Use

^\w+:(?:(?!.*[.!?])(.*))?

See proof.

EXPLANATION

NODE                     EXPLANATION
--------------------------------------------------------------------------------
  ^                        the beginning of the string
--------------------------------------------------------------------------------
  \w+                      word characters (a-z, A-Z, 0-9, _) (1 or
                           more times (matching the most amount
                           possible))
--------------------------------------------------------------------------------
  :                        ':'
--------------------------------------------------------------------------------
  (?:                      group, but do not capture (optional
                           (matching the most amount possible)):
--------------------------------------------------------------------------------
    (?!                      look ahead to see if there is not:
--------------------------------------------------------------------------------
      .*                       any character except \n (0 or more
                               times (matching the most amount
                               possible))
--------------------------------------------------------------------------------
      [.!?]                    any character of: '.', '!', '?'
--------------------------------------------------------------------------------
    )                        end of look-ahead
--------------------------------------------------------------------------------
    (                        group and capture to \1:
--------------------------------------------------------------------------------
      .*                       any character except \n (0 or more
                               times (matching the most amount
                               possible))
--------------------------------------------------------------------------------
    )                        end of \1
--------------------------------------------------------------------------------
  )?                       end of grouping

For the first pattern, you could first check that there is no ! ? or . present using a negative lookahead. Then capture in the first group 1+ word chars and : and the rest of the line in group 2.

^(?![^!?.\n\r]*[!?.])(\w+:)(.*)$
  • ^ Start of string
  • (?! Negative lookahead, assert what is on the right is not
    • [^!?.\n\r]*[!?.] Match 0+ times any char except the listed using contrast, then match either ! ? .
  • ) Close lookahead
  • (\w+:) Capture group 1, match 1+ word chars and a colon
  • (.*) Capture group 2, match any char except a newline 0+ times
  • $ End of string

Regex demo

For the second part, if you want a match only for Choose:, you could use the negative lookahead only without a capturing group.

^(?![^!?.\n\r]*[!?.])\w+:

Regex demo

Related