2015-09-30 1 views
9

Sto cercando di fare un lavoro php regex che analizza una stringa di testo in parentesi, ignorando possibili parentesi nidificate:php regex per rilevare il testo tra parentesi ignorando parentesi nidificate

Diciamo che voglio

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. 

per tornare

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

Finora ho ottenuto

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

ma si interrompe quando si verificano parentesi annidate. See demo

Come posso ignorare le parentesi interne dal rilevamento? Thx in anticipo!

+0

A causa della struttura nidificata, credo che la regex non sia adatta al caso. Forse una semplice routine è un approccio migliore. – someOne

risposta

2

È possibile utilizzare questo modello che cattura il numero dell'articolo e il testo seguente in due gruppi diversi. Se sei sicuro che tutti i numeri sono unici, si può costruire la matrice associativa descritto nella sua domanda con un semplice array_combine:

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

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

dettagli del modello:

~  # 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 

(*) nota che il La parte numero articolo deve essere facoltativa se si desidera essere in grado di utilizzare la ricorsione con (?R)(ad esempio [consectetuer adipiscing] non ha un numero di articolo.). Questo può essere problematico se si desidera evitare parentesi quadre senza numero di articolo. In questo caso è possibile costruire un modello più robusto se si cambia il gruppo opzionale (?:(\d+)\.\s)? ad un'istruzione condizionale: (?(R)|(\d+)\.\s)

dichiarazione condizionale:

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

In questo modo il numero di articolo diventa obbligatoria.

1

È possibile utilizzare una regex ricorsivo per ottenere tutte le stringhe racchiuse tra parentesi quadre, e quindi utilizzare un preg_replace all'interno di un array_map per rimuovere le staffe e staffe allegando:

$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); 

Vedi IDEONE demo

Il \[(?>[^\[\]]|(?R))*] regex corrisponde a [, quindi tutto tranne [ e ] o i costrutti nidificati [...]. Vedi di più sulla ricorsione con espressioni regolari a regular-expressions.info. Ecco lo regex demo.

La regex all'interno preg_repace - ^\[\d+\.(.*?)\s*\]$ - corrisponderà iniziale [ di 1 o più cifre e un periodo successivo, e partita e catturare il resto fino alla spaziatura finale facoltativa (\s*) e chiusura ] (la $ farà sicuro che la parentesi sia abbinata alla fine della stringa). Con $1 possiamo ripristinare il resto della stringa e usarlo per popolare un nuovo array. Vedi lo 2nd regex demo here.

5

È possibile utilizzare riferimenti ricorsivi a gruppi precedenti:

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

See it in action

L'idea è di definire le partite desiderate come sia qualcosa senza staffe, circondato da [] o qualcosa del genere, che contiene una sequenza di nessuna parentesi o parentesi equilibrate con la prima regola.

+0

Non sapevo di gruppi di cattura denominati, molto utile! – hm711

Problemi correlati