3

我有以下字符串:

OPEN有人打招呼CLOSE我正在打招呼人们OPEN有人打招呼OPEN他们再次打招呼CLOSE我现在得走了 虽然CLOSE又打招呼了!

我正在尝试匹配所有出现的hello(未包含在OPENCLOSE单词中)并将它们替换为另一个单词,可能使用正则表达式和 PHP 的preg_replace函数(尽管我对其他方法持开放态度,因为我不能随便想想)。

因此,从上面的字符串中,以下内容将匹配(我将它们放在带有斜体的括号中以帮助您区分):

OPEN有人打招呼CLOSE打招呼你好 )人们OPEN有人打招呼OPEN他们又打招呼

不知道该怎么做。

编辑也许这会更好地阐明嵌套结构:

OPEN
text
CLOSE

OPEN 
text
  OPEN
   text
  CLOSE
text
CLOSE

正如你从上面看到的,你好没有被注意到,因为它在 OPEN...CLOSE 中(所以它们被忽略了),而其他的则不会被替换。

4

3 回答 3

2

艾伦的回答很好。但是,由于我已经花时间编写它,这里有另一种使用回调函数和 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];
}
于 2011-09-28T04:53:23.833 回答
2

我给 s 编号了,hello所以应该被替换。hello2hello5

$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!

演示

前瞻使用递归子模式构造,(?1)尝试OPEN...CLOSE在当前匹配的单词和字符串结尾之间匹配零个或多个完整的嵌套结构。假设所有的OPENs 和CLOSEs 都是适当平衡的,这意味着hello\d它刚刚匹配的不在这样的结构中。

于 2011-09-28T03:42:19.740 回答
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>
于 2011-09-28T02:52:51.263 回答