PHP RegEx: non-kaçtı tırnak dışında bir desen eşleştirme

3 Cevap php

Bir SQL sorgu dizesi belirli veriyi kaldırmak için bir yöntem yazıyorum ve ben outside tek tırnak görünür YALNIZCA kaşlı ayraç içinde herhangi bir kelime maç regex gerekir. Ben de (ters eğik çizgi öncesinde) kaçtı tırnak yanı sıra, kaçan tersbölülerden olasılığı faktör gerekir.

Aşağıdaki örneklerde, ben {FAN} maç regex değil {BAR} gerekir:

blah blah {FOO} blah 'I\'m typing {BAR} here with an escaped backslash \\'
blah blah {FOO} 'Three backslashes {BAR} and an escaped quote \\\\\\\' here {BAR}'

Ben (bu durumda "FON",) parantez içinde kelime almak için PHP preg_match kullanıyorum. İşte ben bugüne kadar sahip regex dize var:

$regex = '/' .
	// Match the word in braces
	'\{(\w+)\}' .
	// Only if it is followed by an even number of single-quotes
	'(?=(?:[^\']*\'[^\']*\')*[^\']*$)' .
	// The end
	'/';

Benim mantık, ben ayrıştırma ediyorum tek şey (Ben ilave ayracı-şey dışında) yasal bir SQL dizesi olduğundan, parantez bir dizi olmayan kaçan tırnak bir even sayısına göre izlediyseniz , o zaman tırnak dışında olmalıdır.

Ben verilen regex dikkate kaçtı tırnak ayırdığınız için DIŞINDA% 100 başarılı. Sadece emin tersbölülerden hiçbir tek sayıda bir alıntı maçtan önce orada olmak gerekiyor, ama beni yaşam için ben RegEx'in bu iletmek için görünmüyor olabilir. Herhangi girenlerin?

3 Cevap

Kaçtı tırnak ve ters eğik çizgi ile başa çıkmak için bir yol eşleşen çiftler onları tüketmektir.

(?=(?:(?:(?:[^\'\\]++|\\.)*+\'){2})*+(?:[^\'\\]++|\\.)*+$)

Başka bir deyişle, bir sonraki teklif için tarama gibi, bir ters eğik çizgi ile başlayan herhangi bir karakter çiftini atlayın. Yani hem tırnak kaçtı ve ters bölü kaçan ilgilenir. Bu ilerleme, muhtemelen gerekli olmadığı, alıntı bölümlerin dışına kaçtı karakter izin verir, ama muhtemelen ya zarar vermez.

ps, iyelik nicelik liberal kullanımını (*+ ve ++) dikkat edin; Bu olmadan, hedef dizeleri büyük, özellikle performans sorunları olabilir. Dizeleri satır sonlarını içerebilir Ayrıca, eğer sen dotall modunda (aka, "SingleLine" veya "/ s" modu) eşleştirme yapmak gerekebilir.

Ancak, ben mmyers ile katılıyorum: SQL ayrıştırmak çalışıyorsanız, size will regexes hiç işleyemez sorunlarla. Regexes kötü olan bütün şeyleri, SQL kötü biridir.

Basitçe, ve belki de safça, tüm çift ters eğik dışarı str_replace. Sonra kaçtı tek tırnak dışarı str_replace. Bu noktada (örneğin mevcut regex kullanarak) tek tırnak arasında değil eşleşmeleri bulmak için nispeten basit.

Eğer gerçekten bu düzenli ifadeler kullanmak istiyorsanız, ben iki adımda bunu:

  1. Ile non-strings arasındaki strings Ayrı preg_split,

    $re = "('(?:[^\\\\']+|\\\\(\\\\\\\\)*.)*')";
    $parts = preg_split('/'.$re.'/', $str, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
    
  2. Değiştir ne de strings:

    foreach ($parts as $key => $val) {
        if (preg_match('/^'.$re.'$/', $val)) {
            $parts[$key] = preg_replace('/\{([^}]*)}/', '$1', $val);
        }
    }
    

Bu yaklaşım bu verimli değil gibi ama gerçek bir ayrıştırıcı muhtemelen daha iyi olurdu.