¿Cómo reemplazo los caracteres latinos acentuados en Ruby?

Tengo un modelo de ActiveRecord , Foo , que tiene un campo de name . Me gustaría que los usuarios puedan buscar por nombre, pero me gustaría que la búsqueda ignore mayúsculas y minúsculas y acentos. Por lo tanto, también estoy almacenando un campo canonical_name contra el cual buscar:

 class Foo validates_presence_of :name before_validate :set_canonical_name private def set_canonical_name self.canonical_name ||= canonicalize(self.name) if self.name end def canonicalize(x) x.downcase. # something here end end 

Necesito completar el “algo aquí” para reemplazar los caracteres acentuados. ¿Hay algo mejor que

 x.downcase.gsub(/[àáâãäå]/,'a').gsub(/æ/,'ae').gsub(/ç/, 'c').gsub(/[èéêë]/,'e').... 

Y, para el caso, dado que no estoy en Ruby 1.9, no puedo poner esos literales Unicode en mi código. Las expresiones regulares reales se verán mucho más feas.

Rails ya tiene un built-in para normalizar, solo tiene que usar esto para normalizar su cadena para formar KD y luego eliminar los otros caracteres (es decir, acentos) como este:

 >> "àáâãäå".mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/n,'').downcase.to_s => "aaaaaa" 

ActiveSupport::Inflector.transliterate (requiere Rails 2.2.1+ y Ruby 1.9 o 1.8.7)

ejemplo:

>> ActiveSupport::Inflector.transliterate("àáâãäå").to_s => "aaaaaa"

Mejor aún es usar I18n:

 1.9.3-p392 :001 > require "i18n" => false 1.9.3-p392 :002 > I18n.transliterate("Olá Mundo!") => "Ola Mundo!" 

He intentado muchos de estos enfoques pero no estaban logrando uno o varios de estos requisitos:

  • Respetar espacios
  • Respetar el carácter ‘ñ’
  • Caso de respeto (sé que no es un requisito para la pregunta original, pero no es difícil mover una cadena a un nivel bajo )

Ha sido esto:

 # coding: utf-8 string.tr( "ÀÁÂÃÄÅàáâãäåĀāĂ㥹ÇçĆćĈĉĊċČčÐðĎďĐđÈÉÊËèéêëĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħÌÍÎÏìíîïĨĩĪīĬĭĮįİıĴĵĶķĸĹĺĻļĽľĿŀŁłÑñŃńŅņŇňʼnŊŋÒÓÔÕÖØòóôõöøŌōŎŏŐőŔŕŖŗŘřŚśŜŝŞşŠšſŢţŤťŦŧÙÚÛÜùúûüŨũŪūŬŭŮůŰűŲųŴŵÝýÿŶŷŸŹźŻżŽž", "AAAAAAaaaaaaAaAaAaCcCcCcCcCcDdDdDdEEEEeeeeEeEeEeEeEeGgGgGgGgHhHhIIIIiiiiIiIiIiIiIiJjKkkLlLlLlLlLlNnNnNnNnnNnOOOOOOooooooOoOoOoRrRrRrSsSsSsSssTtTtTtUUUUuuuuUuUuUuUuUuUuWwYyyYyYZzZzZz" ) 

http://blog.slashpoundbang.com/post/12938588984/remove-all-accents-and-diacritics-from-string-in-ruby

Tienes que modificar un poco la lista de caracteres para respetar el carácter ‘ñ’ pero es un trabajo fácil.

Mi respuesta: el método de parametrización String # :

 "Le cœur de la crémiére".parameterize => "le-coeur-de-la-cremiere" 

Para progtwigs que no son Rails:

Instale activesupport: gem install activesupport luego:

 require 'active_support/inflector' "a&]'s--3\014\xC2àáâã3D".parameterize # => "as-3-3d" 

Creo que tal vez no realmente qué ir por ese camino. Si se está desarrollando para un mercado que tiene este tipo de letras, sus usuarios probablemente pensarán que es una especie de … pip . Porque ‘å’ ni siquiera está cerca de ‘a’ en ningún sentido para un usuario. Tome un camino diferente y lea acerca de la búsqueda de una manera no ascii. Este es solo uno de esos casos que alguien inventó unicode y colación .

Un PD muy tarde :

http://www.w3.org/International/wiki/Case_folding http://www.w3.org/TR/charmod-norm/#sec-WhyNormalization

Además de eso, no tengo ninguna forma de que el enlace a la intercalación vaya a una página msdn, pero la dejo ahí. Debería haber sido http://www.unicode.org/reports/tr10/

Descompón la cuerda y quita las marcas que no estén espaciadas .

 irb -ractive_support/all > "àáâãäå".mb_chars.normalize(:kd).gsub(/\p{Mn}/, '') aaaaaa 

También puede necesitar esto si se usa en un archivo .rb.

 # coding: utf-8 

la parte normalize(:kd) divide aquí diacriticals cuando sea posible (por ejemplo, el carácter individual “n con tilda” se divide en una n seguida de un carácter gsub combinada diacrítica), y la parte gsub luego elimina todos los caracteres diacríticos.

Esto supone que usa Rails.

 "anything".parameterize.underscore.humanize.downcase 

Teniendo en cuenta sus requisitos, esto es probablemente lo que haría … Creo que es limpio, simple y se mantendrá actualizado en versiones futuras de Rails y Ruby.

Actualización: dgilperez señaló que parameterize toma un argumento de separación, por lo que "anything".parameterize(" ") (obsoleto) o "anything".parameterize(separator: " ") es más corto y más limpio.

Convierta el texto a la forma D de normalización, elimine todos los puntos de código con la marca no espaciadora de categoría Unicode (Mn) y conviértalo de nuevo a la forma de normalización C. Esto eliminará todos los signos diacríticos y su problema se reducirá a una búsqueda que no distingue entre mayúsculas y minúsculas.

Consulte http://www.siao2.com/2005/02/19/376617.aspx y http://www.siao2.com/2007/05/14/2629747.aspx para obtener más detalles.

La clave es usar dos columnas en su base de datos: canonical_text y original_text . Use original_text para mostrar y canonical_text para búsquedas. De esta forma, si un usuario busca “Visual Cafe”, ve el resultado “Visual Café”. Si realmente quiere un artículo diferente llamado “Visual Cafe”, se puede guardar por separado.

Para obtener los caracteres canonical_text en un archivo fuente Ruby 1.8, haga algo como esto:

 register_replacement([0x008A].pack('U'), 'S') 

Probablemente desee la descomposición Unicode (“NFD”). Después de descomponer la cadena, simplemente filtra todo lo que no esté en [A-Za-z]. æ se descompondrá en “ae”, ã en “a ~” (aproximadamente – el diacrítico se convertirá en un carácter separado) por lo que el filtrado deja una aproximación razonable.

Para cualquiera que lea esto que quiera despojar a todos los personajes no ascii, esto podría ser útil; utilicé el primer ejemplo con éxito.

Tuve problemas para obtener la solución foo.mb_chars.normalize (: kd) .gsub (/ [^ \ x00- \ x7F] / n, ”). Downcase.to_s para que funcione. No estoy usando Rails y hubo algún conflicto con mis versiones de active support / ruby ​​que no pude llegar al final.

Usar la gem ruby-unf parece ser un buen sustituto:

 require 'unf' foo.to_nfd.gsub(/[^\x00-\x7F]/n,'').downcase 

Por lo que puedo decir, esto hace lo mismo que .mb_chars.normalize (: kd). ¿Es esto correcto? ¡Gracias!

jaja … acabo de probar esto … y está funcionando … iam todavía no estoy muy seguro de por qué … pero cuando uso estas 4 líneas de código:

  • str = str.gsub (/ [^ a-zA-Z0-9] /, “”)
  • str = str.gsub (/ [] + /, “”)
  • str = str.gsub (/ /, “-“)
  • str = str.downcase

elimina automáticamente cualquier acento de los nombres de archivo … que estaba tratando de eliminar (acentuación de los nombres de los archivos y renombrarlos) espero que haya ayudado 🙂