2015-09-30 27 views
9

Mümkün iç içe parantez görmezden parantez içindeki metin için bir dize ayrıştırır bir php regex çalışması yapmaya çalışıyorum görmezden algılamak için: ı istediğinizi varsayalımphp regex parantez içindeki metin iç içe parantez

Lorem ipsum [1. dolor sit amet, [consectetuer adipiscing] elit.]. Aenean commodo ligula eget dolor.[2. Dolor, [consectetuer adipiscing] elit.] Aenean massa[3. Lorem ipsum] dolor. 

dönmek için

[1] => "dolor sit amet, [consectetuer adipiscing] elit." 
[2] => "Dolor, [consectetuer adipiscing] elit." 
[3] => "Lorem ipsum" 

Şimdiye kadar ben

'/\[([0-9]+)\.\s([^\]]+)\]/gi' 
var

ancak yuvalanmış parantezler oluştuğunda kırılır. See demo

İç köşeli parantezleri algılamadan nasıl yok sayabilirim? Thx önceden!

+0

Yuvalanmış yapı nedeniyle, regex'in durum için uygun olmadığına inanıyorum. Belki basit bir rutin daha iyi bir yaklaşımdır. – someOne

cevap

2

Öğe numarasını ve aşağıdaki metni iki farklı grupta toplayan bu deseni kullanabilirsiniz. Tüm öğe numaraları benzersizdir eminseniz, basit array_combine ile soruda açıklandığı ilişkisel dizi inşa edebilirsiniz:

$pattern = '~\[ (?:(\d+)\.\s)? ([^][]*+ (?:(?R) [^][]*)*+) ]~x'; 

if (preg_match_all($pattern, $text, $matches)) 
    $result = array_combine($matches[1], $matches[2]); 

Desen ayrıntıları: O

~  # pattern delimiter 
\[ # literal opening square bracket 
(?:(\d+)\.\s)? # optional item number (*) 
(    # capture group 2 
    [^][]*+   # all that is not a square bracket (possessive quantifier) 
    (?:    # 
     (?R)  # recursion: (?R) is an alias for the whole pattern 
     [^][]*  # all that is not a square bracket 
    )*+    # repeat zero or more times (possessive quantifier) 
) 
]     # literal closing square bracket 
~x # free spacing mode 

(*) notu Özyinelemeyi (?R)ile kullanabilmek için öğe numarası bölümü isteğe bağlı olmalıdır (örneğin [consectetuer adipiscing] ürün numarasına sahip değildir.. Öğe numarası olmadan köşeli ayraçlardan kaçınmak istiyorsanız bu sorun olabilir. Bir koşullu açıklamaya opsiyonel grup (?:(\d+)\.\s)? değiştirirseniz bu durumda daha sağlam bir desen oluşturabilirsiniz: (?(R)|(\d+)\.\s)

Şartlı açıklama: madde numarası zorunlu hale Böylelikle

(?(R)  # IF you are in a recursion 
      # THEN match this (nothing in our case) 
    |   # ELSE 
    (\d+)\.\s # 
) 

.

1

Sen parantez ve çevreleyen parantezleri kaldırmak için bir array_map içinde bir preg_replace kullanmak sonra köşeli parantez ile kapalı tüm alt dizeleri elde etmek için bir özyinelemeli düzenli ifade kullanabilirsiniz ve:

$str = "Lorem ipsum [1. dolor sit amet, [consectetuer adipiscing] elit.]. Aenean commodo ligula eget dolor.[2. Dolor, [consectetuer adipiscing] elit.] Aenean massa[3. Lorem ipsum] dolor."; 
preg_match_all('/\[(?>[^\[\]]|(?R))*]/', $str, $matches); 
$res = array_map(function($el) { 
    return preg_replace('/^\[\d+\.(.*?)\s*\]$/s', '$1', $el); 
    }, 
    $matches[0]); 
print_r($res); 

Bkz IDEONE demo

\[(?>[^\[\]]|(?R))*] regex [ ile eşleşir, daha sonra [ ve ] ya da iç içe [...] yapıları ile ilgilidir. regular-expressions.info numaralı telefondan regex ile özgeçmiş hakkında daha fazla bilgi edinin. İşte regex demo.

preg_repace içinde normal ifade - ^\[\d+\.(.*?)\s*\]$ - 1 ya da daha fazla rakam ve sonra belli bir süre, maç ile ilk [ eşleşen ve son isteğe bağlı boşluk (\s*) ve ] kapatma gerisini çekeceği ($ yapacak desteğin dizenin sonunda eşleştiğinden emin olun). $1 ile dizenin geri kalanını geri yükleyebilir ve yeni bir dizi oluşturmak için kullanabiliriz. 2nd regex demo here'a bakın.

5

Bir önceki gruplara özyinelemeli başvuruları kullanabilirsiniz:

(?<no_brackets>[^\[\]]*){0}(?<balanced_brackets>\[\g<no_brackets>\]|\[(?:\g<no_brackets>\g<balanced_brackets>\g<no_brackets>)*\]) 

See it in action

fikri istediğiniz maçları tanımlamaktır bir diziyi içeriyor [] falan çevrili hiçbir parantez ile ya bir şey gibi ilk kural ile parantez veya dengeli parantezler.

+0

İsim yakalama grupları hakkında çok bilgim yoktu! – hm711

İlgili konular