Seleccione dos palabras consecutivas por expresión regular

Ya que soy nuevo en expresiones regulares; Quiero hacer una expresión regular para seleccionar dos palabras consecutivas.

Por ejemplo, cuando doy esta frase: "¡Hola gente, la expresión #RegularExpression apesta!"

Tiene que devolver estas dos palabras:

-Hola gente

-personas #RegularExpression

- ¡# RegularExpression apesta!

Intenté esto /\w\s\w/i Pero no funcionó :(

preguntado el 30 de agosto de 11 a las 23:08

¿Qué sabor de expresión regular? .net, perl, javascript? -

lo necesito para php. ¿Supongo que es Perl? -

5 Respuestas

$s = "Hello people #RegularExpression sucks!";
preg_match_all('~(?=(\S+\s+\S+))\S+\s+~', $s, $matches);
print_r($matches[1]);

salida:

Array
(
    [0] => Hello people
    [1] => people #RegularExpression
    [2] => #RegularExpression sucks!
)

explicación:

\S+ coincide con uno o más caracteres que no son espacios en blanco. Tu \w era incorrecto por dos razones: solo coincide con un carácter; y solo coincide con un llamado carácter de palabra (equivalente a [A-Za-z0-9_]). Añadiendo el + para usted \s no era necesario en este caso de prueba, pero no hay razón no para agregarlo, y los espacios en blanco adicionales tienen una forma de colarse en el texto en el mundo real. (Pero asegúrese y agregue +no, *; debe haber al menos un carácter de espacio en blanco allí).

(?=...) es un anticipación positiva. Los usa para verificar si es posible para que coincida con la subexpresión incluida en la posición de coincidencia actual, sin seguir la posición del partido. Luego, por lo general, sigue adelante y hace coincidir una subexpresión diferente, no en una búsqueda anticipada.

Aquí está el truco: aunque los caracteres que coinciden con la subexpresión anticipada no son consumido, cualquier grupo de captura en la subexpresión funciona como de costumbre. La mirada hacia adelante en mi expresión regular, (?=(\S+\s+\S+)) cerillas y captura la siguiente secuencia de dos palabras. Luego (asumiendo que la búsqueda anticipada tuvo éxito) \S+\s+ coincidencias de la forma habitual, estableciendo la posición de coincidencia correctamente para el próximo intento.

Esta técnica debería funcionar en cualquier tipo de expresión regular que admita la captura de grupos y búsquedas anticipadas. Eso incluye PHP, así como todos los demás lenguajes principales (Perl, JavaScript, .NET, Python, Java ...). La técnica para acceder solo al contenido del primer grupo de captura de cada coincidencia varía enormemente de un idioma a otro, pero PHP lo hace fácil, con $matches[1].

Respondido 31 ago 11, 10:08

Quiero descartar todos los caracteres no alfanuméricos excepto # y @. ¿Qué debo hacer para esto? - Yunus Eren Güzel

Suena como una pregunta aparte. ¿Quieres descartarlos de los resultados (bastante fácil) o no hacerlos coincidir en primer lugar (no tan fácil)? ¿Pretende descartarlos de palabras individuales o también desea eliminar los espacios entre palabras? En esta página podría resultar útil, aunque sólo sea para formular una pregunta más útil. - Alan Moore

Su expresión regular en realidad coincidiría con dos letras separadas por un espacio. Entonces, con tu aporte obtendrías o p y n s. El otro problema al hacer esto es hacer una búsqueda global de expresiones regulares en una cadena que devuelve instancias que no se superponen. Entonces, una expresión regular adecuada podría regresar Hello people, #RegularExpression sucks!, pero no volvería people #RegularExpression ya que eso se superpone con Hello people. Una tercera pregunta es ¿cómo se define la palabra? La definición clásica, y la utilizada por el \w átomo, es alfanumérico o subrayado. Como tal, #RegularExpression no coincidiría porque # no es un personaje de palabra.

En total, suena como lo que verdaderamente lo que quieres hacer es dividir tu cadena en espacios, y luego puedes recopilar todos los pares de palabras tú mismo. Puedes hacer la división con algo como preg_split('/\s+/', $str) para devolver una matriz de todas las palabras separadas por espacios en blanco, y luego puede iterar sobre la matriz como desee.

Respondido 31 ago 11, 03:08

Estoy bastante seguro de que lo es posible que ver con las expresiones regulares, pero el problema aquí es que las expresiones regulares consumen reloj que coinciden, por lo que "volver" para obtener coincidencias superpuestas es algo complicado de hacer. Regex no es la herramienta adecuada para esto; un martillo no chupa porque no puede manejar (correctamente) los tornillos.

Si yo fuera tú, simplemente haría:

$str =  "Hello people #RegularExpression does not suck!";
$arr = explode(' ', $str);

for ($i=0; $i<count($arr) - 1; $i++) {
    echo implode(' ', array_slice($arr, $i, 2)) . "\n";
}

Salidas:

Hello people
people #RegularExpression
#RegularExpression does
does not
not suck!

Respondido 31 ago 11, 03:08

Como dijeron otros, eso parece imposible (EDITAR: Vaya, eso está mal, vea la respuesta de Alan) en pcre regex estándar, y es mejor que elija otra estrategia.

Permítanme agregar que parece existir una solución experimental y complicada: los verbos retroceder.

Consulte la sección "CONTROL DE RETROCESO" en el documento pcre.org/pcre.txt

Respondido 31 ago 11, 12:08

Si bien no puedo decir con certeza que los verbos de control de retroceso no puedes ser utilizado para esto, puedo decir con confianza que ellos no debe ser. ☺ - Alan Moore

Gracias por tu consejo y tu respuesta, leeré más sobre esto para entender por qué. - fbdcw

Los verbos de control de retroceso son intrigantes, pero nunca he profundizado en ellos porque (1) solo Perl y PCRE (sabores similares pero separados) los admiten, y trato de concentrarme en funciones más ampliamente disponibles; (2) están clasificados como experimentales en ambos sabores; y (3) cada vez que empiezo a leer sobre ellos, me sorprende la sensación de que debería estar leyendo sobre generadores de analizadores sintácticos o PEGs en su lugar. ☺ - Alan Moore

Este patrón debería funcionar:

/[^\s]+\s[^\s]+/i

Coincide con todos los caracteres que no son espacios en blanco seguidos de un único carácter de espacio en blanco y otros caracteres que no son espacios en blanco.

Respondido 31 ago 11, 03:08

$t = 'RT @cerenkilicaslan: #kadinlardaiticiozellikler kisaca Bilkent sarisi diyoruz sacin %10luk kismi siyah,dibi '; $a = preg_split ('/\w+\s\w+/i',$t); print_r($a) que devolvió Array ([0] => RT @cerenkilicaslan: # [1] => [2] => [3] =>% [4] => siyah, dibi) - Yunus Eren Güzel

¿Por qué preg_split? preg_match_all ('/ \ w + \ s \ w + / i', 'RT @cerenkilicaslan: #kadinlardaiticiozellikler kisaca Bilkent sarisi diyoruz sacin% 10luk kismi siyah, dibi', $ arr, PREG_PATTERN_ORDER); print_r ($ arr); funcionó bien para mí. - CANNADARK

Sí, está mal, es tarde aquí (gmt + 2) y tenía demasiado sueño para darme cuenta de que escribí algo mal. Eliminé el comentario cuando lo noté ... Estoy probando otras soluciones sin preg_split pero no obtengo muchos resultados. El último que probé es / \ S + \ s \ S + / i, pero después de encontrar un par, se salta el siguiente. Me pregunto por qué, tal vez debería abrir una nueva pregunta sobre eso ... O_o - CANNADARK

Regex consume lo que coincide. Para obtener coincidencias superpuestas, tendría que hacer que el motor de expresiones regulares "retroceda". Creo que podría hacer que funcione si usa lookaround, pero no he tenido ningún éxito con eso. - NullUserException

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.