¿Cómo obtener todas las capturas de subgrupos coincide con preg_match_all ()?

Actualización / Nota:

Creo que lo que probablemente estoy buscando es obtener las capturas de un grupo en PHP.

Referenciado: expresiones regulares PCRE utilizando subrutinas de patrones con nombre.

(Lea cuidadosamente:)


Tengo una cadena que contiene una cantidad variable de segmentos (simplificada):

$subject = 'AA BB DD '; // could be 'AA BB DD CC EE ' as well 

Me gustaría ahora hacer coincidir los segmentos y devolverlos a través de la matriz de coincidencias:

 $pattern = '/^(([az]+) )+$/i'; $result = preg_match_all($pattern, $subject, $matches); 

Esto solo devolverá la última coincidencia para el grupo de captura 2: DD .

¿Hay alguna manera de que pueda recuperar todas las capturas de subpatrones ( AA , BB , DD ) con una ejecución de expresiones regulares? ¿No es preg_match_all adecuado para esto?

Esta pregunta es una generalización.

Tanto el $pattern $subject como $pattern están simplificados. Naturalmente, tal lista general de AA , BB , … es mucho más fácil de extraer con otras funciones (por ejemplo, explode ) o con una variación del $pattern .

Pero específicamente estoy preguntando cómo devolver todas las coincidencias de subgrupos con la familia de funciones preg_...

Para un caso de la vida real imagine que tiene un nivel múltiple (nested) de una cantidad variante de coincidencias de subpatrones.

Ejemplo

Este es un ejemplo en pseudo código para describir un poco del fondo. Imagina lo siguiente:

Definiciones regulares de tokens:

  CHARS := [az]+ PUNCT := [.,!?] WS := [ ] 

$subject get’s tokenized basado en estos. La tokenización se almacena dentro de una matriz de tokens (tipo, desplazamiento, …).

Esa matriz se transforma en una cadena, que contiene un carácter por token:

  CHARS -> "c" PUNCT -> "p" WS -> "s" 

De modo que ahora es posible ejecutar expresiones regulares basadas en tokens (y no clases de caracteres, etc.) en el índice de cadena de secuencia de token. P.ej

  regex: (cs)?cp 

para express uno o más grupos de caracteres seguidos de una puntuación.

Como ahora puedo express tokens autodefinidos como expresiones regulares, el siguiente paso fue construir la gramática. Esto es solo un ejemplo, esta es una especie de estilo ABNF:

  words = word | (word space)+ word word = CHARS+ space = WS punctuation = PUNCT 

Si ahora compilo la gramática de las palabras en una expresión regular (token) me gustaría tener naturalmente todas las coincidencias de subgrupos de cada palabra .

  words = (CHARS+) | ( (CHARS+) WS )+ (CHARS+) # words resolved to tokens words = (c+)|((c+)s)+c+ # words resolved to regex 

Podría codificar hasta este punto. Luego me encontré con el problema de que las coincidencias del subgrupo solo contenían su última coincidencia.

Así que tengo la opción de crear un autómata para la gramática por mi cuenta (lo que me gustaría evitar para mantener genéricas las expresiones gtwigticales) o de alguna manera hacer que preg_match me funcione de alguna manera, así que puedo evitarlo.

Eso es básicamente todo. Probablemente ahora es comprensible por qué simplifiqué la pregunta.


Relacionado:

  • página de manual de pcrepattern
  • Obtenga coincidencias repetidas con preg_match_all ()

Prueba esto:

 preg_match_all("'[^ ]+'i",$text,$n); 

$n[0] contendrá una matriz de todos los grupos de caracteres que no sean espacios en el texto.

Editar: con subgrupos:

 preg_match_all("'([^ ]+)'i",$text,$n); 

Ahora $n[1] contendrá las coincidencias de subgrupo, que son exactamente las mismas que $n[0] . Esto es inútil en realidad.

Edit2: ejemplo de subgrupos nesteds:

 $test = "Hello I'm Joe! Hi I'm Jane!"; preg_match_all("/(H(ello|i)) I'm (.*?)!/i",$test,$n); 

Y el resultado:

 Array ( [0] => Array ( [0] => Hello I'm Joe! [1] => Hi I'm Jane! ) [1] => Array ( [0] => Hello [1] => Hi ) [2] => Array ( [0] => ello [1] => i ) [3] => Array ( [0] => Joe [1] => Jane ) ) 

No puede extraer los subpatrones porque la forma en que escribió su expresión regular devuelve una sola coincidencia (usando ^ y $ al mismo tiempo, y + en el patrón principal).

Si lo escribe de esta manera, verá que sus subgrupos están allí correctamente:

 $pattern = '/(([az]+) )/i'; 

(Esto todavía tiene un par de paréntesis innecesarios, simplemente lo dejé allí para su ilustración)

¿Hay alguna manera de que pueda recuperar todas las coincidencias (AA, BB, DD) con una ejecución de expresiones regulares? ¿No es preg_match_all no adecuado para esto?

Su expresión regular actual parece ser para una llamada a preg_match (). Pruebe esto en su lugar:

 $pattern = '/[az]+/i'; $result = preg_match_all($pattern, $subject, $matches); 

Por comentarios, el Ruby regex que mencioné:

 sentence = %r{ (? cat | dog ){0} (? eats | drinks ){0} (? water | bones ){0} (? big | smelly ){0} (? (\g\s)? ){0} The\s\g\g\s\g\s\g\g }x md = sentence.match("The cat drinks water"); md = sentence.match("The big dog eats smelly bones"); 

Pero creo que necesitarás un lexer / analizador / tokenizador para hacer el mismo tipo de cosas en PHP. : – |

Tema similar: Obtenga coincidencias repetidas con preg_match_all ()

Verifique la respuesta elegida más la mía que pueda ser útil. Haré la duplicación allí:

Desde http://www.php.net/manual/en/regexp.reference.repetition.php :

Cuando se repite un subconjunto de captura, el valor capturado es la subcadena que coincidió con la iteración final.

Personalmente, me rindo y voy a hacer esto en 2 pasos.

Editar

No me di cuenta de lo que originalmente había pedido. Aquí está la nueva solución:

 $result = preg_match_all('/[az]+/i', $subject, $matches); $resultArr = ($result) ? $matches[0] : array(); 

Qué tal si:

 $str = 'AA BB CC'; $arr = preg_split('/\s+/', $str); print_r($arr); 

salida:

 ( [0] => AA [1] => BB [2] => CC ) 

Puede que haya entendido mal lo que describes. ¿Estás buscando un patrón para grupos de letras con espacios en blanco entre?

 // any subject containing words: $subject = 'AfdfdfdA BdfdfdB DdD'; $subject = 'AA BB CC'; $subject = 'Af df dfdA Bdf dfdB DdD'; $pattern = '/(([az]+)\s)+[az]+/i'; $result = preg_match_all($pattern, $subject, $matches); print_r($matches); echo "
"; print_r($matches[0]); // this matches $subject echo "
".$result;

Sí, tiene razón en que su solución es mediante preg_match_all preg_match_all es recursiva, por lo tanto, no use start-with ^ y end-with $ , de modo que preg_match_all coloque todos los patrones encontrados en una matriz.

Cada nuevo par de paréntesis agregará un Nuevo conjunto que indica las diferentes coincidencias

uso ? para partidos opcionales

Puede separar diferentes grupos de patrones reportados con el paréntesis () para pedir que se encuentre un grupo y se agregue en una nueva matriz (puede permitirle contar las coincidencias, o categorizar cada una de las coincidencias de la matriz devuelta)

Se requiere aclaración

Déjame intentar entender tu pregunta, para que mi respuesta coincida con lo que preguntas.

  1. Su $subject no es un buen ejemplo de lo que está buscando?

  2. ¿Desea realizar la búsqueda de preejecución, dividir lo que proporcionó en $subject en 4 categorías , Palabras , Caracteres , Puntuación y espacios en blanco ? y ¿qué pasa con los números ?

  3. Además, ¿desea que las coincidencias devueltas tengan las compensaciones de las coincidencias especificadas?

Does $subject = 'aa.bb cc.dd EE FFF,GG'; encajar mejor en un ejemplo de la vida real?

Tomaré tu ejemplo básico en $subject y haré que funcione para dar exactamente tu pregunta.

Entonces, ¿puedes editar tu $subject para que se ajuste mejor a todos los casos que quieras combinar?

Original '/^(([az]+) )+$/i';

Manténganme informado, pueden probar sus expresiones regulares aquí http://www.spaweditor.com/scripts/regex/index.php

Respuesta parcial

/([az])([az]+)/i

AA BB DD CD

 Array ( [0] => Array ( [0] => AA [1] => BB [2] => DD [3] => CD ) [1] => Array ( [0] => A [1] => B [2] => D [3] => C ) [2] => Array ( [0] => A [1] => B [2] => D [3] => D ) )