我有以下字符串:
OPEN 有人打招呼 CLOSE 即时通讯打招呼人 OPEN 有人说 你好 OPEN 他们再次打招呼 CLOSE 我现在必须走了 CLOSE 再次问好!
我正在尝试匹配所有 hello (未包含在 OPEN 和 CLOSE 字词中)并将其替换为另一个词,可能是正则表达式和PHP的preg_replace
函数(虽然我对其他方法持开放态度,因为我无法想到)。
因此,从上面的字符串开始,下面的内容将匹配(我已将它们放在带斜体的括号中以帮助您区分):
OPEN 有人说你好 CLOSE 我说(你好)人 OPEN 有人说 你好 OPEN 他们再次打招呼 CLOSE 我现在必须再去 CLOSE ( hello )了!
不太确定如何做到这一点。
编辑或许这将更好地阐明嵌套结构:
OPEN
text
CLOSE
OPEN
text
OPEN
text
CLOSE
text
CLOSE
正如你从上面所看到的那样,hello没有被注意到,因为它在OPEN ... CLOSE内(所以它们被忽略),而其他的不会被替换。
答案 0 :(得分:2)
我为hello
编号,因此hello2
和hello5
应该被替换。
$s0 = 'OPEN someone said hello1 CLOSE im saying hello2 people OPEN some said hello3 OPEN they said hello4 again CLOSE i have to go now though CLOSE hello5 again!';
$regex='~
hello\d
(?=
(?:(?!OPEN|CLOSE).)*+
(?:
(
OPEN
(?:
(?:(?!OPEN|CLOSE).)*+
|
(?1)
)*
CLOSE
)
(?:(?!OPEN|CLOSE).)*+
)?
$
)
~x';
$s1=preg_replace($regex, 'goodbye', $s0);
print($s1);
输出:
OPEN someone said hello1 CLOSE im saying goodbye people OPEN some said hello3 OPEN they said hello4 again CLOSE i have to go now though CLOSE goodbye again!
<强> demo 强>
前瞻使用递归子模式构造(?1)
来尝试匹配当前匹配的单词和字符串结尾之间的零个或多个完整的嵌套OPEN...CLOSE
结构。假设所有OPEN
和CLOSE
都得到了适当的平衡,这意味着它匹配的hello\d
在这样的结构中而不是。
答案 1 :(得分:2)
(?R)
递归表达式的方法:
function highlightNonNestedHello($str) {
$re = '/# Two global alternatives. Either...
( # $1: Non-O..C stuff.
(?: # Step through non-O..C chars.
(?!\b(?:OPEN|CLOSE)\b) # If not start of OPEN or CLOSE,
. # then match next char.
)+ # One or more non-O..C chars.
) # End $1:
| # Or...
( # $2: O..C stuff.
\bOPEN\b # Open literal delimiter.
(?R)+ # Recurse overall regex.
\bCLOSE\b # Close literal delimiter.
) # End $1:
/sx';
return preg_replace_callback($re, '_highlightNonNestedHello_cb', $str);
}
function _highlightNonNestedHello_cb($matches) {
// Case 1: Non-O...C stuff. Highlight all "hello".
if ($matches[1]) {
return preg_replace('/\bhello\b/', '(HELLO)', $matches[1]);
}
// Case 2: O...C stuff. Preserve as-is.
return $matches[2];
}
答案 2 :(得分:0)
这是我的尝试,告诉我它是否适合你:
<?php
$str = 'OPEN someone said hello CLOSE im saying hello people OPEN some said hello OPEN they said hello again CLOSE i have to go now though CLOSE hello again!';
echo "<p>$str</p>"; //before
//first replace all of them
$str = str_replace('hello', '(hello)', $str);
//then replace back only those within OPEN CLOSE
function replace_back($match){return str_replace('(hello)', 'hello', $match[0]);}
$str = preg_replace_callback('/OPEN.*?\(hello\).*?CLOSE/', 'replace_back', $str);
echo "<p>$str</p>"; //after
?>
<style>p{width:500px;background:#F1F1F1;padding:10px;font:13px Arial;}</style>