preg_grep - preg_match_all ejemplos php
¿Cómo obtener todas las capturas de coincidencias de subgrupos con preg_match_all()? (8)
Actualización / Nota:
Creo que lo que probablemente estoy buscando es obtener las capturas de un grupo en PHP.
Referenciado: expresiones regulares de PCRE que utilizan subrutinas de patrones con nombre.
(Lea cuidadosamente:)
Tengo una cadena que contiene un número variable de segmentos (simplificado):
$subject = ''AA BB DD ''; // could be ''AA BB DD CC EE '' as well
Ahora me gustaría hacer coincidir los segmentos y devolverlos a través de la matriz de coincidencias:
$pattern = ''/^(([a-z]+) )+$/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 poder recuperar todas las capturas de subpatrones ( AA
, BB
, DD
) con una ejecución de expresiones regulares? ¿No es apropiado preg_match_all
para esto?
Esta pregunta es una generalización.
Tanto el $subject
$pattern
se simplifican. Naturalmente, con la 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 estoy preguntando específicamente cómo devolver todas las coincidencias de subgrupos con la familia de funciones preg_...
_....
Para un caso de la vida real, imagine que tiene varios niveles (anidados) de una cantidad variable 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 := [a-z]+
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 en clases de caracteres, etc.) en el índice de cadenas de token. P.ej
regex: (cs)?cp
para expresar uno o más grupos de caracteres seguidos de una puntuación.
Como ahora puedo expresar tokens autodefinidos como expresiones regulares, el siguiente paso fue construir la gramática. Esto es solo un ejemplo, esto 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 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 de subgrupos 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 las expresiones gramaticales genéricas) o hacer que preg_match funcione de alguna manera para que pueda ahorrar eso.
Eso es básicamente todo. Probablemente ahora es comprensible por qué simplifiqué la pregunta.
Relacionado:
¿Hay alguna forma de recuperar todas las coincidencias (AA, BB, DD) con una ejecución de expresiones regulares? ¿No es apropiado preg_match_all para esto?
Tu regex actual parece ser para una llamada preg_match (). Intenta esto en su lugar:
$pattern = ''/[a-z]+/i'';
$result = preg_match_all($pattern, $subject, $matches);
Por comentarios, el rubex regex que mencioné:
sentence = %r{
(?<subject> cat | dog ){0}
(?<verb> eats | drinks ){0}
(?<object> water | bones ){0}
(?<adjective> big | smelly ){0}
(?<obj_adj> (/g<adjective>/s)? ){0}
The/s/g<obj_adj>/g<subject>/s/g<verb>/s/g<opt_adj>/g<object>
}x
md = sentence.match("The cat drinks water");
md = sentence.match("The big dog eats smelly bones");
Pero creo que necesitarás un lexer / parser / tokenizer para hacer el mismo tipo de cosas en PHP. : - |
No puedes extraer los subpatrones porque la forma en que escribiste tu expresión regular devuelve solo una coincidencia (usando ^
y $
al mismo tiempo, y +
en el patrón principal).
Si lo escribe de esta manera, verá que sus subgrupos están correctamente allí:
$pattern = ''/(([a-z]+) )/i'';
(Esto todavía tiene un conjunto innecesario de paréntesis, lo dejé allí para ilustración)
Prueba esto:
preg_match_all("''[^ ]+''i",$text,$n);
$n[0]
contendrá una matriz de todos los grupos de caracteres que no son espacios en el texto.
Edición: con subgrupos:
preg_match_all("''([^ ]+)''i",$text,$n);
Ahora $n[1]
contendrá las coincidencias de subgrupos, que son exactamente iguales a $n[0]
. Esto es inútil en realidad.
Edit2: ejemplo de subgrupos anidados:
$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
)
)
Puede que haya entendido mal lo que estás describiendo. ¿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 = ''/(([a-z]+)/s)+[a-z]+/i'';
$result = preg_match_all($pattern, $subject, $matches);
print_r($matches);
echo "<br/>";
print_r($matches[0]); // this matches $subject
echo "<br/>".$result;
Qué tal si:
$str = ''AA BB CC'';
$arr = preg_split(''//s+/'', $str);
print_r($arr);
salida:
(
[0] => AA
[1] => BB
[2] => CC
)
Sí, su solución es que usar preg_match_all
preg_match_all es recursivo, así que no use start-with ^
y end-with $
, de modo que preg_match_all
ponga todos los patrones encontrados en una matriz.
Cada par de paréntesis nuevo agregará una Nueva matriz indicando las diferentes coincidencias
utilizar ?
para partidos opcionales
Puede separar diferentes grupos de patrones reportados con paréntesis ()
para solicitar que se encuentre un grupo y se agregue en una nueva matriz (puede permitirle contar coincidencias o categorizar cada una de las coincidencias de la matriz devuelta)
Se requiere aclaración
Déjame tratar de entender tu pregunta, para que mi respuesta coincida con lo que preguntas.
¿Su
$subject
no es un buen ejemplo de lo que está buscando?¿Le gustaría que la búsqueda previa coincida, dividiera lo que proporcionó en
$subject
en 4 categorías , palabras , caracteres , puntuación y espacios en blanco ? y que pasa con los numeros¿Le gustaría también que las coincidencias devueltas tengan las compensaciones de las coincidencias especificadas?
Hace $subject = ''aa.bb cc.dd EE FFF,GG'';
¿Se ajusta mejor un ejemplo de la vida real?
Tomaré su ejemplo básico en $subject
y haré que funcione para darle exactamente lo que pidió.
Entonces, ¿puedes editar tu $subject
para que me ajuste mejor a todos los casos que quieras emparejar?
Original ''/^(([az]+) )+$/i'';
Mantenerme informado, puedes probar tus 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
)
)
Tema similar: Consigue coincidencias repetidas con preg_match_all ()
Verifique que la respuesta elegida más la mía pueda ser útil. Voy a duplicar allí:
De http://www.php.net/manual/en/regexp.reference.repetition.php :
Cuando se repite un subpatrón de captura, el valor capturado es la subcadena que coincide con la iteración final.
Personalmente me rindo y voy a hacer esto en 2 pasos.
EDITAR :
Veo en ese otro hilo que someone afirmó que el método de mirar por detrás es capaz de hacerlo.
Editar
No me di cuenta de lo que habías pedido originalmente. Aquí está la nueva solución:
$result = preg_match_all(''/[a-z]+/i'', $subject, $matches);
$resultArr = ($result) ? $matches[0] : array();