0

I am looking for a regex that will find a match ...

  1. The start of the match is :!
  2. The middle can contain anything BUT another :! string
  3. The end of the match is !:

  • Example 1: Chicken :!fnDeepFry(Funky:Cheese)!: Wings

    • Expected Match: :!fnDeepFry(Funky:Cheese)!:
  • Example 2: Chicken :!fnDeepFry(:!fnSpecial({{recIngred}})!:)!: Wings

    • Expected Match: :!fnSpecial({{recIngred}})!:

Here is my attempt ... /:!([^:!]+)!:/gm

I can't get the match box [^:!] to recongize :! as a string, and not individual characters.

https://regex101.com/r/gGPcRu/1

Wiktor Stribiżew
  • 484,719
  • 26
  • 302
  • 397
bbullis
  • 504
  • 7
  • 20
  • reg exp seems like a bad choice, should be a parser.... – epascarello Oct 27 '20 at 04:10
  • thank you for the suggestion, but parser is unfortunately not an option for me. I don't know regex well, but I was hoping adjusting the regex to invalidate a match if string `:!` exists wouldn't be overly difficult. @epascarello – bbullis Oct 27 '20 at 04:18
  • You actually need `/:!((?:(?!:!).)+)!:/g`, see [demo](https://regex101.com/r/gGPcRu/3). `/.*:!(.*?)!:/g` is a regex that matches the last occurrence of your pattern, it will not be able to match multiple ones on the same line. – Wiktor Stribiżew Oct 27 '20 at 09:59

2 Answers2

1

Seems to me there is a simple enough solution:

REGEX:

/.*:!(.*?)!:/    
 .*:!           : Greedy [.*] select everything until last ":!" which is then followed by the rest of the regex
     (.*?)      : Non-greedy capture group. Captures everything until first occurrence of rest of regex
          !:    : End of match

Input:

Chicken :!fnDeepFry(Funky:Cheese)!: Wings
Chicken :!fnDeepFry(:!fnSpecial({{recIngred}})!:)!: Wings
Chicken :! :!fnDeepFry(:!fnSpecial({{recIngred}})!:)!: Wings

Output:

fnDeepFry(Funky:Cheese)
fnSpecial({{recIngred}})
fnSpecial({{recIngred}})
Steven
  • 5,830
  • 2
  • 11
  • 26
  • That worked for my use case. It grabs the inner function and a simple loop captured the rest. Thanks for the quick reply, going live! – bbullis Oct 27 '20 at 04:28
0

Here's my take on it:

:!([^!:]+(?:(?:![^:]|:[^!])[^!:]*)*)!:

What this does is:

  1. Match the literal value :!
  2. match anything that isn't an ! or a : multiple times
  3. Match zero or more times the following group:
    1. (literal ! followed by anything that isn't a :) Or a (literal : followed by anything that isn't a !)
    2. Zero or more of anything that isn't an ! or a :
  4. literal :!

This uses a technique called unrolling the loop. It's more complicated to wrap your head around, but if you want better performance, this will be a better option than non-greedy qualifiers.

https://regex101.com/r/gGPcRu/2

Zachary Haber
  • 7,380
  • 1
  • 6
  • 19