创建互斥但不重叠的正则表达式

A template engine processes both {{foo}} and {{{bar}}}, they correspond to different treatments.

Currently, the source is processed with preg_replace's like so: {{\s*(.+?)\s*}} and {{{\s*(.+?)\s*}}}.

The problem is, these regexes overlap, e.g. {{\s*(.+?)\s*}} matches in {{{bar}}}.


Important note: the markers {{, {{{, }}, }}} are user-configurable in the real code. So usual solutions like [^{}] cannot be used.


The current solution is to replace {{{ }}}'s before {{ }}'s, but that's not robust enough. Indeed, the markers being user-configurable, the user can easily set the markers to values which break the app.

I'm trying to make robuster regexes which are mutually exclusive, not order-dependant. I've already tried using assertions, conditionals, etc. without success. Any help would be greatly appreciated.

By the way, use of regex is not mandatory, as long as the code doesn't become overlong.

sounds like you need to try some lookarounds. Here is my sample which shows the two different matches tests

$Matches = @()
$String = 'A template{{{bar}}} engine processes both {{foo}} and {{{bar}}}, they correspond to different treatments.'
write-host "Foo matches"
([regex]'(?<!{){{([^{}]*)}}(?!})').matches($String) | foreach {
    write-host "at $($_.Groups[1].Index) = '$($_.Groups[1].Value)'"
    } # next match

Write-Host 
write-host "Bar matches"
$Matches = @()
([regex]'{{{([^{}]*)}}}').matches($String) | foreach {
    write-host "at $($_.Groups[1].Index) = '$($_.Groups[1].Value)'"
    } # next match

yields

Foo matches
at 44 = 'foo'

Bar matches
at 13 = 'bar'
at 57 = 'bar'

I've modified your inner text test to look for any non "} or "{" characters this way all characters inside are returned.