Soy bastante nuevo en expresiones regulares y estoy atascado en lo siguiente donde trato de usar preg_match_all para contar el número de hola después del mundo .
Si uso "world".+(hello) , cuenta hasta el último hola ; "world".*?(hello) se detiene en el primer hello , ambos dan una cuenta.
blah blah blah hello blah blah blah class="world" blah blah blah hello blah blah hello blah blah blah hello blah blah blah Estoy esperando 3 como el conteo porque el hello antes del world no debe contarse.
Otra opción con expresiones regulares simples:
if(preg_match('/"world".*/s', $str, $out)) { echo preg_match_all('/\bhello\b/', $out[0]); }Puede usar una sola llamada preg_match_all aquí:
$text = "blah blah blah\nhello\nblah blah blah\nclass=\"world\" \nblah blah blah\nhello \nblah blah\nhello\nblah blah blah\nhello\nblah blah blah"; echo preg_match_all('~(?:\G(?!^)|\bworld\b).*?\K\bhello\b~s', $text);Vea la demostración de expresiones regulares y la demostración de PHP . Detalles :
(?:\G(?!^)|\bworld\b) - final de la coincidencia anterior ( \G(?!^) verifica esto: \G coincide con el inicio de la cadena o con el final de la posición de coincidencia anterior , por lo tanto, debemos excluir el inicio de la posición de la cadena, y esto se hace con (?!^) anticipación negativa) o un world de palabras completo.*? - cualquier cero o más caracteres, la menor cantidad posible\K - descarta todo el texto coincidente hasta el momento\bhello\b - una palabra completa hello . NOTA : si no necesita la verificación de límites de palabras, puede eliminar \b del patrón.
Si hello y world son patrones definidos por el usuario, debe preg_quote en el patrón:
$start = "world"; $find = "hello"; $text = "blah blah blah\nhello\nblah blah blah\nclass=\"world\" \nblah blah blah\nhello \nblah blah\nhello\nblah blah blah\nhello\nblah blah blah"; echo preg_match_all('~(?:\G(?!^)|' . preg_quote($start, '~') . '\b).*?\K' . preg_quote($find, '~') . '~s', $text);De otra manera: fuerce el patrón para que falle y no vuelva a intentarlo si world no existe en la cadena:
~(?:\A(*COMMIT).*?world)?.*?hello~s El grupo que no captura es opcional pero codicioso. En consecuencia, se prueba cada vez que se prueba el patrón.
Comienza con el ancla \A que coincide con el inicio de la cadena, por lo que esta es la única posición en la que este grupo puede tener éxito. Después del comienzo de la cadena, en otras posiciones \A falla y dado que el grupo es opcional, el subpatrón restante se ignora y la búsqueda continúa con .*?hello .
Inmediatamente después, está el verbo de control de retroceso (*COMMIT) que, en caso de falla posterior, obliga a que el patrón no se vuelva a intentar en absoluto. (El final de la historia).
En otras palabras, si este grupo falla al comienzo de la cadena, la investigación se aborta de una vez por todas.
Ventaja: necesita menos pasos que un patrón basado en \G .
Para ser más eficiente, un patrón basado en \G también se puede escribir de esta manera (usando un grupo opcional en lugar de una alternancia):
~(?:\A.*?world)?(?!\A).*?hello~sA Aquí el modificador A toma el rol del ancla \G , pero es exactamente lo mismo que comenzar cada rama de un patrón (solo una aquí) con el ancla \G .