php - neden bu regex sıfır uzunlukta benim dize kesecek nedir?

4 Cevap

Üzerinde hiçbir içerik, görünür hiçbir hata mesajı - Dün bir web sitesi ekran sadece beyaz bir sayfa neden garip bir hata izini.

Ben preg_replace kullanılan bir düzenli ifade sorun olduğunu gördük.

Sadece html echo'ing önce birikmiş içerik başlıktaki html etiketi değiştirmek için, düzenli ifade kullanılır. Html bug (60 kb - çok büyük değil) meydana sayfada oldukça büyük var ve preg_replace gibi / kullanılan regex sadece belirli uzunlukta bir dize işleyebilir gibiydi - ya da benim regex (gerçekten de mümkündür) berbat.

(PHP 5.2.9 üzerinde test) sorunu reproduces bu örnek programda bakın:


function replaceTitleTagInHtmlSource($content, $replaceWith) {
  return preg_replace('#(<title>)([\s\S]+)(<\/title>)#i', '$1'.$replaceWith.'$3', $content);
}


$dummyStr = str_repeat('A', 6000);

$karşıtalStr = '<title>foo</title>';

for($i = 0; $i < 10; $i++) {
  $karşıtalStr .= $dummyStr;
}

print 'orignal: ' . strlen($karşıtalStr);
print '<hr />';

$replaced = replaceTitleTagInHtmlSource($karşıtalStr, 'bar');

print 'replaced: ' . strlen($replaced);
print '<hr />';

Çıktı:

orignal: 60018
replaced: 0

Yani - fonksiyon uzunluğu 60000 bir dize alır ve 0 uzunlukta bir dize döndürür. Ne ben benim regex yapmak istedim.


Değişen

for($i = 0; $i < 10; $i++) {

karşı

for($i = 0; $i < 1; $i++) {

in order karşı decrease the karşıtal string length, the output is:

orignal: 6018
replaced: 6018


Ben değiştirirken kaldırıldı zaman, sayfanın içeriği herhangi bir sorun olmadan sergilendi.

4 Cevap

Eğer backtracking limit içine koşuyoruz gibi görünüyor.

Eğer preg_last_error() : it returns PREG_BACKTRACK_LIMIT_ERROR yazdırmak bu teyit edilmektedir.

Sen o kadar geriye onu durduracak olan, ini dosyası sınırını artırmak veya ini_set() or change your regular expression from ([\s\S]+) .*? kullanarak ya.

Bu etiketleri çok düzensiz olduğu için regexes HTML için uygun olmadığını SO, örneğin http://stackoverflow.com/questions/1458280/regex-to-match-the-first-ending-html-tag (ve muhtemelen tekrar söz edilecektir) daha önce birçok kez söylenmiş thas.

Kullanılabilir olduklarında DOM işlevlerini kullanın.

Yararlar: [\s\S]+ TÜM mevcut karakterleri maç olacak, daha sonra </title> arıyor dize geriye doğru gidin. [^<]+ < olmayan tüm karakterleri ile eşleşir ve bu nedenle </title> daha hızlı kapmak.

function replaceTitleTagInHtmlSource($content, $replaceWith) {
  return preg_replace('#(<title>)([^<]+)(</title>)#i', '$1'.$replaceWith.'$3', $content);
}

Sizin regex biraz komik gibi görünüyor.

([\ S \ S] +) tüm uzay ve non-boşluk eşleşir. denemelisiniz (. *?) yerine.

Lütfen değişen işlevi benim için çalışıyor:

function replaceTitleTagInHtmlSource($content, $replaceWith) {
  return preg_replace('`\<title\>(.*?)\<\/title\>`i', '<title>'.$replaceWith.'</title>', $content);
}

ve sorun maç ve $ 1 ve $ 3 kullanmaya çalışıyor gibi görünüyor