Ruby, sustituyendo matches de una regex en un String con matches de la misma regex
Madre mÃa que tÃtulo bueno me ha quedado :)
Esto es una nota mental y puede que si no sabes de que hablo no te interese y si sabes de que hablo ya lo sepas.
Intento sustituir una parte de un String por otra parte que se encuentra en el mismo String.
Es decir, tengo esto “me gusta el heavy y no me gusta el country” y quiero obtener esto otro “me gusta el country y no me gusta el heavy”.
Se puede hacer asÃ:
>> "me gusta el heavy y no me gusta el country".gsub( /me gusta (.*) y no me gusta el (.*)/, 'me gusta \2 y no me gusta el \1' ) => "me gusta country y no me gusta el el heavy"
Donde \1 y \2 son las ocurrencias de los (.*).
El ejemplo puede parecer un poco tonto, pero esta utilidad me ha venido muy bien para quedarme con el contenido de una etiqueta html:
>> "<body>contenido</body>".gsub( /.*<body[^>]*>(.*)<\/body>.*/mix, '\1' ).strip => "contenido"
Que se puede solucionar de muchas otras maneras pero esta me ha parecido la más sencilla.
Escribo esta nota mental por lo poco intuitivo que es el uso de ‘\1′ como cadena sustitutiva pues se supone que las cadenas entre comillas simples no se interpretan…
Otra cosa es que google siempre me llevaba a soluciones como esta:
>> "me gusta el heavy y no me gusta el country".gsub( /me gusta (.*) y no me gusta el (.*)/, "me gusta #{$2} y no me gusta el #{$1}" ) => "me gusta country y no me gusta el el heavy"
Y aunque parece que funciona no es asà porque los contenidos de $1 y $2 los ha cogido del gsub anterior y no de éste:
>> "me gusta el musical y no me gusta el flamenco".gsub( /me gusta (.*) y no me gusta el (.*)/, "me gusta #{$2} y no me gusta el #{$1}" ) => "me gusta country y no me gusta el el heavy" >> "me gusta el musical y no me gusta el flamenco".gsub( /me gusta (.*) y no me gusta el (.*)/, "me gusta #{$2} y no me gusta el #{$1}" ) => "me gusta flamenco y no me gusta el el musical"
Septiembre 5th, 2008 at 10:11 am
Hola Fernando, estoy disfrutando de tus posts sobre Ruby y aprendiendo contigo. Mi dos cientos de euro (un anglisismo?) es que quizas sea mas intuitivo usar scan or =~ cuando quieres sacar algo del string i no sustituir.
Asi tu ejemplo seria:
o bien:
Con =~ :
y tienes ‘contenido’ en $1.
Keep your Ruby posts coming!
Balint
Septiembre 5th, 2008 at 10:21 am
IMHO hay formas más directas para el caso de obtener un substring:
Los backreferences (\1, \2…) son más útiles y están pensados para cuando se usan dentro de la propia REGEXP:
Septiembre 5th, 2008 at 11:11 am
Balint: Mi dos cientos de euro => Mis dos céntimos de euro :)
Septiembre 5th, 2008 at 11:20 am
Balint, Aitor: Os he reparado los comentarios pues el cabroncete del wordpress se come muchos caracteres importantes. Espero no haber metido la pata :)
Septiembre 5th, 2008 at 11:22 am
Balint, tienes toda la razón de que el gsub no era buena solución para mi intento de extraer el contenido de una tag xml, además de lioso no respondÃa bien pues en caso de no encontrar ningún match con la regex devolvÃa todo el string y no es correcto.
Si no hay match no se deberÃa devolver nada.
De hecho, al final mi metodo extractor de bodys queda asÃ:
Septiembre 5th, 2008 at 11:23 am
Aitor, increÃblemente instructivos tus ejemplos de malabarismos con regexs, no se me habrÃan ocurrido :)
Septiembre 5th, 2008 at 2:24 pm
Ya pensaba que hay solucion mas elegante que la mia, sino no seria ruby :) (Gracias, Aitor)
Septiembre 5th, 2008 at 2:26 pm
Porque dos centimos? Dos cientos son mejor, no? ;)
Julio 12th, 2009 at 5:32 pm
En realidad la solución buena es usar el ‘xxx \1′ con comillas simples:
>> “me gusta el musical y no me gusta el flamenco”.gsub( /me gusta (.*) y no me gusta el (.*)/, ‘me gusta \2 y no me gusta el \1′ )
=> “me gusta flamenco y no me gusta el el musical”
Noviembre 16th, 2009 at 1:41 am
Hola, y como lo harÃas si tienes dos select en un string, y quieres sacar primero un contenido y luego el otro