简体   繁体   中英

PHP - How can regex replace a string by condition

I have a string:

{include "abc"}

{literal} 

function xyz() {

       "ok";

   }

{/literal}

{abc}

{123 }

I just want to replace all { to {{ and } to }} not in {literal} tag. The result will be:

{{include "abc"}}

{{literal}}

   function xyz() {

       "ok";

   }

   //... something contain { and }

{{/literal}}

{{abc}}

{123 }}

Someone can help me, Thanks

You can do it with this pattern:

$pattern = '~(?:(?<={literal})[^{]*(?:{(?!/literal})[^{]*)*+|[^{}]*)([{}])\K~'

$text = preg_replace($pattern, '$1', $text);

demo

pattern details:

~                       # pattern delimiter
(?:                     # non-capturing group
    (?<={literal})      # lookbehind: preceded by "{literal}"
                        # a lookbehind doesn't capture any thing, it is only a test
    [^{]*               # all that is not a {
    (?:
        {(?!/literal})  #/# a { not followed by "/literal}"
        [^{]*
    )*+                 # repeat as needed
  |                     # OR
    [^{}]*              # all that is not a curly bracket,
                        # (to quickly reach the next curly bracket)
)
([{}])                  # capture a { or a } in group 1
\K                      # discards all on the left from match result
                        # (so the whole match is empty and nothing is replaced,
                        # the content of the capture group is only added 
                        # with the replacement string '$1')
~

Notes: this pattern assumes that {literal} can't be nested and always closed. If {literal} can stay unclosed, it is possible to force this default behavior: "an unclosed {literal} is considered as open until the end of the string" .

To do that you can change the capture group to ([{}]|(*COMMIT)(*F)) . When the first branch [{}] fails, this means that the end of the string is reached. The (*COMMIT) verb forces the regex engine to stop all research in the string when the pattern fails after, and (*F) forces it to fail. So all after {literal} stay unchanged.

Regex:

(?s)(?<=\{literal\}).*?(?=\{\/literal\})(*SKIP)(*F)|([{}])

Replacement string:

\1\1

DEMO

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM