替换所有未包含在 OPEN 和 CLOSE 中的特定单词的出现?
Posted
技术标签:
【中文标题】替换所有未包含在 OPEN 和 CLOSE 中的特定单词的出现?【英文标题】:Replacing all occurences of a specific word which are not enclosed with the words OPEN and CLOSE? 【发布时间】:2011-11-26 12:11:45 【问题描述】:我有以下字符串:
OPEN有人打招呼CLOSE我打招呼的人OPEN有人说 你好OPEN他们又打招呼了CLOSE我现在得走了虽然CLOSE你好!
我正在尝试匹配所有出现的 hello(未包含在 OPEN 和 CLOSE 词中)并将它们替换为另一个词,可能带有正则表达式和 php 的 preg_replace
函数(尽管我对其他方法持开放态度,因为我想不出任何方法)。
所以从上面的字符串中,下面会匹配(我用斜体将它们放在括号中以帮助您区分):
打开有人说你好CLOSE我说(你好)人打开有人说 你好OPEN他们又打招呼了CLOSE我现在得走了,虽然CLOSE(hello)又来了!
不知道该怎么做。
编辑也许这会更好地阐明嵌套结构:
OPEN
text
CLOSE
OPEN
text
OPEN
text
CLOSE
text
CLOSE
正如您从上面看到的,hello 没有被注意到,因为它在 OPEN...CLOSE(因此它们被忽略)内,而其他没有被替换。
【问题讨论】:
如果在您的示例中最后一个 CLOSE 之前有一个“hello”,您是否希望它匹配? 为什么OPEN
OPEN
里面的那个没变?如果这是一个错误,那么我找到了一种方法来执行此操作,如果不是,我需要了解更改脚本的原因。
【参考方案1】:
艾伦的回答效果很好。但是,由于我已经花时间编写它,这里有另一种使用回调函数和 PHP (?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】:我将hello
s 编号,所以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
lookahead 使用递归子模式构造 (?1)
来尝试匹配零个或多个完整的嵌套 OPEN...CLOSE
结构在当前匹配的单词和字符串结尾之间。假设所有OPEN
s 和CLOSE
s 都适当平衡,这意味着它刚刚匹配的hello\d
不在这样的结构中。
【讨论】:
我更喜欢你的——它不需要使用回调函数。 +1【参考方案3】:这是我的尝试,告诉我它是否适合你:
<?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>pwidth:500px;background:#F1F1F1;padding:10px;font:13px Arial;</style>
【讨论】:
以上是关于替换所有未包含在 OPEN 和 CLOSE 中的特定单词的出现?的主要内容,如果未能解决你的问题,请参考以下文章
对#include <iconv.h>、`libiconv_open'、`libiconv'、`libiconv_close' 的未定义引用