Forum: Rails-ES Sustituir tildes en String

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
César D. (Guest)
on 2009-04-11 19:52
Hola,

Llevo varios días intentando sustituir las letras con tildes o
caracteres latinos de una palabra y ya he probado con varias soluciones
que he encontrado por Internet sin éxito.

Lo que quiero es dada por ejemplo la palabra "camión", transformarla en
"camion", o "España" por "Espana". El caso es que con varias soluciones
que he encontrado por Internet consigo que todo funcione correctamente
desde la consola de Ruby, pero luego cuando ejecuto mi aplicación RoR en
Netbeans no funciona. Desde el entorno Netbeans "camión" me retornaría
"camon", es decir, me trunca los caracteres en vez de sustituirlos.

Aquí os dejo un ejemplo del código que estoy utilizando para hacer esta
conversión. (Hago alguna cosa más como sustituir los espacios en blanco
por '-' y pasarlo todo a minúsculas, pero eso sí funciona)

  def nice_slug(str)

    accents = {
      ['á','à','â','ä','ã'] => 'a',
      ['Ã','Ä','Â','À','Á'] => 'A',
      ['é','è','ê','ë'] => 'e',
      ['Ë','É','È','Ê'] => 'E',
      ['í','ì','î','ï'] => 'i',
      ['Í','Î','Ì','Ï'] => 'I',
      ['ó','ò','ô','ö','õ'] => 'o',
      ['Õ','Ö','Ô','Ò','Ó'] => 'O',
      ['ú','ù','û','ü'] => 'u',
      ['Ú','Û','Ù','Ü'] => 'U',
      ['ç'] => 'c', ['Ç'] => 'C',
      ['ñ'] => 'n', ['Ñ'] => 'N'
      }
    accents.each do |ac,rep|
      ac.each do |s|
      str = str.gsub(s, rep)
      end
    end
    str = str.gsub(/[^a-zA-Z0-9 ]/,"")

    str = str.gsub(/[ ]+/," ")


    str = str.gsub(/ /,"-")

    str = str.downcase

  end

¿Alguna idea?
Ruben D. (Guest)
on 2009-04-11 20:11
(Received via mailing list)
Tal vez algo como esto podria ayudar:

>> "camión".mb_chars.decompose.scan(/[a-zA-Z0-9]/).join
=> "camion"

Saludos.
Borja Martín (Guest)
on 2009-04-11 20:11
(Received via mailing list)
Rails añadió el método 'parameterize' a la clase String:
"camión".parameterize
Mira a ver si te sirve

Saludos
César D. (Guest)
on 2009-04-12 18:17
Borja Martín wrote:
> Rails añadió el método 'parameterize' a la clase String:
> "camión".parameterize
> Mira a ver si te sirve
>
> Saludos

Ya lo he probado y sigue sin funcionar :(. Si la cadena a convertir no
lleva tilde, funciona correctamente, en cambio, si lo intento con una
cadena con una tilde el error es el siguiente:

undefined method `normalize' for "Te Contar�n:String

c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.2.2/lib/active_support/inflector.rb:283:in
`transliterate'
c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.2.2/lib/active_support/inflector.rb:262:in
`parameterize'
c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.2.2/lib/active_support/core_ext/string/inflections.rb:106:in
`parameterize'
César D. (Guest)
on 2009-04-12 18:23
Ruben Davila wrote:
> Tal vez algo como esto podria ayudar:
>
>>> "camión".mb_chars.decompose.scan(/[a-zA-Z0-9]/).join
> => "camion"
>
> Saludos.


Hola,

En efecto, desde la consola de Rails me funciona, pero cuando lanzo la
aplicación y depuro con Netbeans me da error:

undefined method `decompose' for "La Traves�a:String

¿Dónde está el problema? ¿Por qué en consola sí funciona y cuando
ejecuto la aplicación en Mongrel no?

Un saludo.
Gunnar W. (Guest)
on 2009-04-12 22:23
(Received via mailing list)
César Díaz dijo [Sat, Apr 11, 2009 at 05:52:37PM +0200]:
> Hola,
>
> Llevo varios días intentando sustituir las letras con tildes o
> caracteres latinos de una palabra y ya he probado con varias soluciones
> que he encontrado por Internet sin éxito.
>
> Lo que quiero es dada por ejemplo la palabra "camión", transformarla en
> "camion", o "España" por "Espana". El caso es que con varias soluciones
> (...)

Umh... Nuevamente -y se darán cuenta que es una óptica que me ha
marcado- creo que lo que tienes que hacer es preguntarte _para qué_
estás haciendo esto. Si bien hasta hace unos años (antes de que
Unicode fuera aceptado comunmente) sí podías hablar de ventajas de
quitar los diacríticos, reduciendo los caracteres de 8 a 7 bits (esto
es, para caber en el subconjunto US-ASCII), hoy esto ya no tiene
sentido.

Para ahorrarme el escribir lo que mucha gente ha escrito sin duda
mejor que yo respecto a Unicode, te sugiero fuertemente asomarte a la
siguiente liga:

    http://www.joelonsoftware.com/articles/Unicode.html
    The Absolute Minimum Every Software Developer Absolutely,
    Positively Must Know About Unicode and Character Sets (No
    Excuses!) (Joel Spolsky)

Y un poquito para poderte refirir a lo que escribo a continuación:

    http://inamidst.com/stuff/unidata/
    Unicode Codepoint Chart

Una de las peculiaridades que nos impone Unicode es que... ya no
existe una sóla manera de escribir las cosas. Me arriesgo a enviar
aquí caracteres que algunos clientes de correo mal configurados no
mostrarán bien. Pero bueno - ¿Ves alguna diferencia entre las
siguientes letras?

    á  á

Son completamente distintas. La primera es un sólo caracter, una a
acentuada (U+00E1). El segundo _debe_ verse igual, pero son dos
caracteres: Una 'a' sencilla (U+0061) seguida de un acento agudo
combinante (U+0301).

Una cuestión muy importante de los caracteres combinantes es que
varios de ellos pueden caer sobre de la misma letra:

    a̅́́

Esa es una 'a' (U+0061) con acento agudo (U+0301), grave (U+0300) y
línea superior (U+0305).

Y claro, hay muchos otros que pueden verse muy similares. Este correo
lo escribo en texto plano (no cambio de tipo de letra ni nada por el
estilo), y si el font con que lees el correo lo soporta, verás algunas
variaciones:

    Esto es texto simple

¿Y por qué te insisto en todo esto? Porque para Ruby y para la base de
datos, naturalmente, estas cadenas se van a representar con la
secuencia de caracteres (típicamente con una codificación UTF8)
correspondiente. Incluso si los ves en la consola de Ruby (cabe
mencionar que los puntos UTF normalmente los expresas como U+xxxx,
donde xxxx es un número de 32 bits en representación hexadecimal; lo
que ves en la representación interna de Ruby en este caso es el
Unicode representado como un conjunto de bytes en UTF8, con los bytes
no-imprimibles representados en octales - La primer liga que mencioné
lo explica), te los muestra explicitando su descomposición. Por
ejemplo:

>> ['á', 'á', 'à́̅', 'Esto es texto simple']
=> ["\303\241", "a\314\201", "a\314\200\314\201\314\205",
"\357\274\245\357\275\223\357\275\224\357\275\217
\357\275\205\357\275\223
\357\275\224\357\275\205\357\275\230\357\275\224\357\275\217
\357\275\223\357\275\211\357\275\215\357\275\220\357\275\214\357\275\205"]
>> ['á', 'á', 'à́̅', 'Esto es texto simple'].map 
{|str| str.size}
=> [2, 3, 7, 54]

Y, por último, a punto al que iba: ¿Cómo puedes compararlas o
asegurarte que una á es realmente el caracter que creías? Obviamente
los elementos primero y segundo -que se ven idénticos- son diferentes,
dado que su longitud en bytes es distinta. Ahora, si agregamos
caracteres de composición (tomo la à́̅ como ejemplo), ¿qué pasa si
los aplicamos en un órden distinto?

>> comp = ['à́̅', 'a̅́̀', 'á̅̀']
=> ["a\314\200\314\201\314\205", "a\314\205\314\201\314\200",
"\303\241\314\205\314\200"]
>> comp[0] == comp[1]
=> false
>> comp[0] == comp[2]
=> false
>> comp[1] == comp[2]
=> false

Las tres grafías son semánticamente equivalentes, pero su
representación varía dado que el órden en que les puse los acentos es
distinto.

... Y nuevamente, ¿todo esto para qué? Para demostrar que no tiene
sentido intentar encontrar la única representación base, al menos no
con una sencilla tabla de equivalencias. Más bien, habría que
preguntarnos si tiene sentido quitar los diacríticos. ¿Para qué
quieres hacerlo? Si es para facilitar las búsquedas, más bien querrás
usar una biblioteca como Soundex, mucho más elaborada que los esquemas
que han presentado ante tu pregunta.

Saludos,

--
Gunnar W. - removed_email_address@domain.invalid - (+52-55)5623-0154 / 1451-2244
PGP key 1024D/8BB527AF 2001-10-23
Fingerprint: 0C79 D2D1 2C4E 9CE4 5973  F800 D80E F35A 8BB5 27AF
Raul M. (Guest)
on 2009-04-12 23:03
(Received via mailing list)
2009/4/12 Gunnar W. <removed_email_address@domain.invalid>:
> Umh... Nuevamente -y se darán cuenta que es una óptica que me ha
> marcado- creo que lo que tienes que hacer es preguntarte _para qué_
> estás haciendo esto. Si bien hasta hace unos años (antes de que
> Unicode fuera aceptado comunmente) sí podías hablar de ventajas de
> quitar los diacríticos, reduciendo los caracteres de 8 a 7 bits (esto
> es, para caber en el subconjunto US-ASCII), hoy esto ya no tiene
> sentido.

Por el código de ejemplo diría que quiere usar algo más que ids en las
URLs con el truco del to_param[1]. Yo creo que en ese caso concreto sí
tiene sentido.

César: he probado el "camión".parameterize que te proponía Borja en
consola y parece funcionar tanto en rails2.2.2 como en la 2.3.2... (No
lo he probado en Windows, quizá la consola te esté jugando una mala
pasada?

Si no te sirve ese método te recomendaría testear alguno de los
múltiples plugins[2] que realizan esa conversión para ver si te
encajan (recalco lo de testear porque algunos directamente ignoran los
caracteres acentuados y no parece que te conformes con eso). Si
ninguno te encaja o lo quieres usar para otra cosa, puedes ver
cómohacen la conversión examinando su código fuente y aplicarlo en tu
proyecto:

[1] http://www.notsostupid.com/blog/2006/07/07/urls-on-rails/
[2]
http://github.com/search?type=Repositories&languag...
Jesús García Carrero (Guest)
on 2009-04-13 10:52
(Received via mailing list)
Buenas César,

Si en la consola funciona bien seguramente el problema esté en tus
archivos. Comprueba que el encoding es correcto. Rails no se lleva muy
bien con las tildes si el encoding del archivo no es utf8.

P.d. Si este es el problema y los archivos implicados no están en utf8 y
los conviertes, seguramente se te descorromoñen las palabras con tildes,
comiéndose alguna letra pegada a ellas (parecido a lo que te pasa cuando
pruebas desde rails y que no pasa desde consola). Espero que ayude.
Guillermo (Guest)
on 2009-04-13 13:44
(Received via mailing list)
¿Has provado ha hacer: ?

Iconv.iconv('ascii//ignore//translit', 'utf-8', string).to_s

Es lo que usa internamente rails para hacer la (inflector.rb:277 aprox)

Es lo que usa parameterize.

Y además está encapsulado en un método documentado llamado transliterate
http://api.rubyonrails.org/classes/ActiveSupport/I...

Para llamarla desde consola puedes hacer
ActiveSupport::Inflector.transliterate(string)


A mi me funciona bastante bien, y nunca he tenido ningún problema.

Un Saludo.
César D. (Guest)
on 2009-04-13 19:38
Hola,

Después de probar algunas de las soluciones aquí propuestas, he
conseguido el resultado que quería utilizando el código del método
transliterate:

string.mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]+/, '')


Respondiendo a Gunnar W. acerca de si realmente tengo necesidad de
realizar esa conversión la respuesta es que necesito construir unas URLs
para extraer datos de determinadas páginas web de terceros a través de
screen scraping, y las URLs de estas páginas no utilizan caracteres
acentuados y demás (obviamente).

Un saludo, y muchas gracias a todos por vuestras respuestas.
Gunnar W. (Guest)
on 2009-04-13 22:09
(Received via mailing list)
César Díaz dijo [Mon, Apr 13, 2009 at 05:38:26PM +0200]:
> para extraer datos de determinadas páginas web de terceros a través de
> screen scraping, y las URLs de estas páginas no utilizan caracteres
> acentuados y demás (obviamente).

¿Por qué "obviamente"?

Los URLs pueden contener texto acentuado sin ningún problema. Para un
buen ejemplo, asómate a http://www.tinyarro.ws/ - o, aunque tu cliente
de correo no lo muestre correctamente (o sí, no lo sé), en la
siguiente dirección:

    http://✩.ws/➡➨➯➔➞➽➹✩✿❥›⌘‽☁

Saludos,

--
Gunnar W. - removed_email_address@domain.invalid - (+52-55)5623-0154 / 1451-2244
PGP key 1024D/8BB527AF 2001-10-23
Fingerprint: 0C79 D2D1 2C4E 9CE4 5973  F800 D80E F35A 8BB5 27AF
This topic is locked and can not be replied to.