15

Lets say I have the following string: "BENffew123X\r\nBENx432f456X\r\nBEN!233789X\r\nBEN4545789X" I want to have a regex that will catch "BEN!233789", it has to lookup non-greedily for "BEN", followed by any character (excluding the word "BEN") and ending with 789X. I tried the regex: /BEN.+?789X/miand I get "BENffew123X\r\nBENx432f456X\r\nBEN!233789X" as a match. I understand that this regex looks for the first "BEN" and catches the start of the string, but I want it to look for the "BEN" which is closest to the first "789X". How can I achieve that? One Idea is to reverse the string, should I do it?

benams
  • 4,308
  • 9
  • 32
  • 74

1 Answers1

24

You need to make sure that BEN isn't present in the text between BEN and 789X. You can do this using a negative lookahead assertion:

/BEN(?:(?!BEN).)*?789X/mi

See it live on regex101.com.

Explanation:

BEN      # Match "BEN"
(?:      # Start of non-capturing group that matches...
 (?!BEN) # (if "BEN" can't be matched here)
 .       # any character
)*?      # Repeat any number of times, as few as possible
789X     # Match 789X
Tim Pietzcker
  • 328,213
  • 58
  • 503
  • 561
  • What does `*?` mean ? – Arup Rakshit Feb 09 '14 at 12:48
  • 2
    Non-greedy `*` (as comment says 'as few as possible'). – Michael Kohl Feb 09 '14 at 12:49
  • 1
    @ArupRakshit: "Zero or more repetitions (`*`), as few as possible (`?`)". So if you have `BEN...789X...789X` it will stop the match at the first `789X`. – Tim Pietzcker Feb 09 '14 at 12:49
  • 1
    @TimPietzcker Thanks. I understand now from this - [how to make Regular expression into non-greedy?](http://stackoverflow.com/questions/2824302/how-to-make-regular-expression-into-non-greedy) – Arup Rakshit Feb 09 '14 at 12:52
  • Wrapping the negative lookahead in a non-capturing group is a really great idea -- especially if, like me, you're fixing a bug in an existing system and the later logic depends on the exact set of captures. Have an upvote! – Jazz Feb 03 '17 at 17:20