3

セミコロンがHTMLエンティティの一部でない限り、各セミコロンの後にスペースを挿入しようとしています。ここでの例は短いですが、私の文字列は非常に長く、いくつかのセミコロンがある(またはない)場合があります。

Coca‑Cola =>     Coca‑Cola  (‑ is a non-breaking hyphen)
Beverage;Food;Music => Beverage; Food; Music

短い文字列のトリックを行う次の正規表現を見つけました。

<?php
$a[] = 'Coca&#8209;Cola';
$a[] = 'Beverage;Food;Music';
$regexp = '/(?:&#?\w+;|[^;])+/';
foreach ($a as $str) {
    echo ltrim(preg_replace($regexp, ' $0', $str)).'<br>';
}
?>

ただし、文字列がやや大きい場合、preg_replace上記は実際にApacheサーバーをクラッシュさせます(ページの読み込み中にサーバーへの接続がリセットされました)。上記のサンプルコードに以下を追加します。

$a[] = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. '.
   'In blandit metus arcu. Fusce eu orci nulla, in interdum risus. '.
   'Maecenas ut velit turpis, eu pretium libero. Integer molestie '.
   'faucibus magna sagittis posuere. Morbi volutpat luctus turpis, '.
   'in pretium augue pellentesque quis. Cras tempor, sem suscipit '.
   'dapibus lacinia, dolor sapien ultrices est, eget laoreet nibh '.
   'ligula at massa. Cum sociis natoque penatibus et magnis dis '.
   'parturient montes, nascetur ridiculus mus. Phasellus nulla '.
   'dolor, placerat non sem. Proin tempor tempus erat, facilisis '.
   'euismod lectus pharetra vel. Etiam faucibus, lectus a '.
   'scelerisque dignissim, odio turpis commodo massa, vitae '.
   'tincidunt ante sapien non neque. Proin eleifend, lacus et '.
   'luctus pellentesque;odio felis.';

上記のコード(大きな文字列を使用)はApacheをクラッシュさせますが、コマンドラインでPHPを実行すると機能します。

私のプログラムの他の場所では、preg_replaceはるかに大きな文字列を問題なく使用しているので、正規表現の何かがPHP/Apacheを圧倒していると思います。

それで、大きな文字列でApacheで動作するように正規表現を「修正」する方法はありますか、それともこれを行う別のより安全な方法がありますか?

助けがあれば、WindowsXPSP3のApache2.0.64でPHP5.2.17を使用しています。(残念ながら、PHPまたはApacheのいずれかをアップグレードすることは今のところオプションではありません。)

4

3 に答える 3

2

私はこの一致式を提案します:

\b(?<!&)(?<!&#)\w+;

...これは、アンパサンド(またはアンパサンドの後にハッシュ記号が続く)が前にないが、セミコロンが後に続く一連の文字(文字、数字、およびアンダースコア)に一致します。

それは次のことを意味するように分解されます:

\b          # assert that this is a word boundary
(?<!        # look behind and assert that you cannot match
 &          # an ampersand
)           # end lookbehind
(?<!        # look behind and assert that you cannot match
 &#         # an ampersand followed by a hash symbol
)           # end lookbehind
\w+         # match one or more word characters
;           # match a semicolon

文字列に置き換えます'$0 '

これがうまくいかない場合はお知らせください

もちろん、セミコロンの一致を避ける[a-zA-Z0-9]代わりに使用することもできますが\w、それで問題が発生することはないと思います

また、次のように、ハッシュ記号もエスケープする必要がある場合あります(これは正規表現のコメント記号であるため)。

\b(?<!&)(?<!&\#)\w+;

編集わからないが、単語の境界を最初に置くと、少し効率的になる(したがってサーバーがクラッシュする可能性が低くなる)と推測しているので、式と内訳でそれを変更しました。 ..

編集2 ...そしてあなたの表現があなたのサーバーをクラッシュさせるかもしれない理由についてもう少し情報:壊滅的なバックトラッキング-これは当てはまると思います(?)うーん....それでも良い情報

セミコロンの後にスペースがまだない場合にのみスペースを追加する場合(つまり、の場合は空白を追加しますが、の場合は追加しpellentesque;odioませんpellentesque; odio)、最後に先読みを追加します。これにより、追加される余分な不要なスペース:

\b(?<!&)(?<!&\#)\w+;(?!\s)
于 2012-04-04T21:12:16.310 に答える
0

このような問題では、コールバックが役立つ場合があります。

(&(?:[A-Za-z_:][\w:.-]*|\#(?:[0-9]+|x[0-9a-fA-F]+)))?;

拡張

(          # Capture buffer 1
   &                              # Ampersand '&'
   (?: [A-Za-z_:][\w:.-]*         # normal words
     | \#                         # OR, code '#'
       (?: [0-9]+                       # decimal
         | x[0-9a-fA-F]+                # OR, hex 'x'
       )
   )
)?         # End capture buffer 1, optional
;          # Semicolon ';'

テストケースhttp://ideone.com/xYrpg

<?php

$line = '
  Coca&#8209;Cola
  Beverage;Food;Music
';

$line = preg_replace_callback(
        '/(&(?:[A-Za-z_:][\w:.-]*|\#(?:[0-9]+|x[0-9a-fA-F]+)))?;/',
        create_function(
            '$matches',
            'if ($matches[1])
               return $matches[0];
             return $matches[0]." ";'
        ),
        $line
    );
echo $line;
?> 
于 2012-04-04T22:46:29.450 に答える
0

ネガティブな後読みを使用できます。

preg_replace('/(?<=[^\d]);([^\s])/', '; \1', $text)

手元にコンピューターがないためテストされていませんが、これまたはそのわずかなバリエーションで動作するはずです。

于 2012-04-04T20:56:30.633 に答える