3

私は次の文字列を持っています:

OPEN誰かがこんにちはと言ったCLOSEimがこんにちは人々と言っているOPENいくつかがこんにちはと言ったOPEN彼らが再びこんにちはと言ったCLOSE私は今行かなければならないがCLOSE再びこんにちは!

helloのすべての出現箇所( OPENおよびCLOSEの単語で囲まれていない)を照合し、それらを別の単語に置き換えようとしています。おそらく、正規表現とPHPのpreg_replace関数を使用します(ただし、他のメソッドを使用することはできません)。考えてみてください)。

したがって、上記の文字列から、以下が一致します(区別しやすいように、イタリック体の括弧で囲んでいます)。

OPEN誰かがこんにちはと言ったCLOSEim言っている(こんにちは)人々OPENいくつかが言ったこんにちはOPEN彼らは再びこんにちはと言ったCLOSE私はもう一度CLOSEこんにちは)が行かなければならない!

これを行う方法がよくわかりません。

おそらくこれを編集すると、ネスト構造がより明確になります。

OPEN
text
CLOSE

OPEN 
text
  OPEN
   text
  CLOSE
text
CLOSE

上からわかるように、helloはOPEN ... CLOSE内にあるため(無視されます)、他のアレントは置き換えられるため、通知されません。

4

3 に答える 3

2

私はhellosに番号を付けたので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)、0個以上の完全なネストされた構造を一致させようとします。すべてのsとsが適切にバランスが取れているOPEN...CLOSEと仮定すると、それはちょうど一致したものがそのような構造の内部にないことを意味します。OPENCLOSEhello\d

于 2011-09-28T03:42:19.740 に答える
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 に答える
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 に答える