Preg_replace if not inside double quotes

Basically, I want to replace certain words (for example, the word "tree" with the word "pizza") in sentences. Restriction: when the word to be replaced is between double quotes, the replacement must not be performed.

Example:

The tree is green. -> REPLACE tree WITH pizza
"The" tree is "green". -> REPLACE tree WITH pizza
"The tree" is green. -> DONT REPLACE
"The tree is" green. -> DONT REPLACE
The ""tree is green. -> REPLACE tree WITH pizza

Can this be done with regular expressions? I would count the number of double quotes before the word and check if it is odd or even. But is this possible using preg_replace in php?

Thanks!

// EDIT:

At the moment, my code is as follows:

preg_replace("/tree/", "pizza", $sentence)

But the problem here is the implementation of double-quoted logic. I tried things like:

preg_replace("/[^"]tree/", "pizza", $sentence)

, , . , . - , .

+4
5

- , , . , .

Negative Lookahead.

$text = preg_replace('/\btree\b(?![^"]*"(?:(?:[^"]*"){2})*[^"]*$)/i', 'pizza', $text);

. Working demo

:

\b               the boundary between a word char (\w) and not a word char
 tree            'tree'
\b               the boundary between a word char (\w) and not a word char
(?!              look ahead to see if there is not:
 [^"]*           any character except: '"' (0 or more times)
  "              '"'
 (?:             group, but do not capture (0 or more times)
  (?:            group, but do not capture (2 times):
   [^"]*         any character except: '"' (0 or more times)
    "            '"'
  ){2}           end of grouping
 )*              end of grouping
 [^"]*           any character except: '"' (0 or more times)
 $               before an optional \n, and the end of the string
)                end of look-ahead

, php

$text = preg_replace('/"[^"]*"(*SKIP)(*FAIL)|\btree\b/i', 'pizza', $text);

. Working demo

, . , , ", , , (*SKIP) (*FAIL) backtracking.

+6

, :

~".*?"(*SKIP)(*FAIL)|\btree\b~s

:

~                   # start delimiter (we could have used /, #, @ etc...)
"                   # match a double quote
.*?                 # match anything ungreedy until ...
"                   # match a double quote
(*SKIP)(*FAIL)      # make it fail
|                   # or
\btree\b            # match a tree with wordboundaries
~                   # end delimiter
s                   # setting the s modifier to match newlines with dots .

PHP- preg_quote(), . :

$search = 'tree';
$replace = 'plant';
$input = 'The tree is green.
"The" tree is "green".
"The tree" is green.
"The tree is" green.
The ""tree is green.';

$regex = '~".*?"(*SKIP)(*FAIL)|\b' . preg_quote($search, '~') . '\b~s';
$output = preg_replace($regex, $replace, $input);
echo $output;

- -     - PHP

+3

tree lookahead:

$pattern = '~\btree\b(?=([^"]|("[^"]*"))*$)~im';

$str = '
The tree is green. -> REPLACE tree WITH pizza
"The" tree is "green". -> REPLACE tree WITH pizza
"The tree" is green. -> DONT REPLACE
"The tree is" green. -> DONT REPLACE
The ""tree is green. -> REPLACE tree WITH pizza';

echo "<pre>".preg_replace($pattern,"pizza",$str)."</pre>";

tree, , , , [^"] "[^"]*" , (PCRE_CASELESS) m (PCRE_MULTILINE).

! : -)

+1

tree(?=(?:(?:[^"]*"){2})*[^"]*$) gm

:
tree(?=[^"]*") "tree", ,
tree(?=([^"]*"){2}) ~
tree(?=(([^"]*"){2})*) ~ ,

tree(?=(([^"]*"){2})*[^"]*) ~,
tree(?=(([^"]*"){2})*[^"]*$) ~
tree(?=(?:(?:[^"]*"){2})*[^"]*$) ,

php

0

JS, . sofar, , . , .

/*
Regular expression group 'NotBetween'.
*/
function rgxgNotBetween($chars, $sep="|")
{
    $chars = explode($sep, $chars);

    $NB = [];

    foreach($chars as $CHR){
        //(*PRUNE) steps over $CHR when it is escaped; that is, preceded by a backslash.
        $NB[] = "(?:$CHR(?:\\\\$CHR(*PRUNE)|.)*?$CHR)";
    }

    $NB = join("|", $NB);

    return "(?:(?:$NB)(*SKIP)(*FAIL))";
}

function jsIdReplace($search, $replace, $source)
{
    $search = ""

    //SKIP further matching when between...
    //double or single qoutes or js regular expression slashes
    .rgxgNotBetween("\x22|\x27|\/")

    //match when NO preceding '.' and no ending ':' (object properties)
    ."|(?:(?<!\.)\b$search\b(?!:))"

    //but do match when preceding '?' or ':' AND ending ':' (ternary statements)
    ."|(?:(?<=\?|:)\b$search\b(?=:))";

    return preg_replace($search, $replace, $source);
}

function jsNoComments($source)
{
    //js comment markers NOT between quotes
    $NBQ = rgxgNotBetween("\x22|\x27");

    //block comments
    $source = preg_replace("#$NBQ|/\*.*?\*/#s", "", $source);

    //line comments; not preceded by backslash
    $source = preg_replace("#$NBQ|\h*(?<!\\\\)//.*\n?#", "", $source);

    return $source;
}
0

All Articles