Come sostituire i caratteri latini accentati in Ruby?

Ho un modello ActiveRecord , Foo , che ha un campo name . Mi piacerebbe che gli utenti fossero in grado di cercare per nome, ma mi piacerebbe che la ricerca ignorasse il caso e qualsiasi accento. Pertanto, sto anche memorizzando un campo canonical_name su cui cercare:

 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 

Devo compilare il “qualcosa qui” per sostituire i caratteri accentati. C’è qualcosa di meglio di

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

E, del resto, dato che non sono su Ruby 1.9, non riesco a inserire quei letterali Unicode nel mio codice. Le espressioni regolari attuali appariranno molto più brutte.

Rails ha già un builtin per la normalizzazione, devi solo usarlo per normalizzare la tua stringa per formare KD e quindi rimuovere gli altri caratteri (cioè i segni di accento) in questo modo:

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

ActiveSupport::Inflector.transliterate (richiede Rails 2.2.1+ e Ruby 1.9 o 1.8.7)

esempio:

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

Meglio ancora è usare I18n:

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

Ho provato molti di questi approcci ma non stavano raggiungendo uno o più di questi requisiti:

  • Rispetta gli spazi
  • Rispettare il carattere “ñ”
  • Rispetto caso (so che non è un requisito per la domanda originale, ma non è difficile spostare una stringa in lowcase )

È stato questo:

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

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

Devi modificare un po ‘la lista dei caratteri per rispettare il carattere “ñ” ma è un lavoro facile.

La mia risposta: il metodo di parametro String # :

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

Per i programmi non Rails:

Installare activesupport: gem install activesupport then:

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

Penso che forse non riesci davvero a seguire questa strada. Se stai sviluppando per un mercato che ha questo tipo di lettere, i tuoi utenti probabilmente penseranno che sei una specie di … pip . Perché “å” non è nemmeno vicino a “a” in alcun senso per un utente. Prendi una strada diversa e leggi le ricerche in modo non asettico. Questo è solo uno di quei casi in cui qualcuno ha inventato l’unicode e le regole di confronto .

Un PS molto recente :

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

Oltre a questo non ho alcun modo ide il collegamento alla collation andare a una pagina msdn ma lascio lì. Dovrebbe essere http://www.unicode.org/reports/tr10/

Decomponi la stringa e rimuovi i segni di non spaziatura da essa.

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

Potrebbe anche essere necessario se utilizzato in un file .rb.

 # coding: utf-8 

la parte normalize(:kd) qui divide i diacritici laddove ansible (es: il carattere singolo “n with tilda” viene diviso in un n seguito da un carattere diacritico di tilda) e la parte gsub rimuove quindi tutti i caratteri diacritici.

Questo presuppone l’utilizzo di Rails.

 "anything".parameterize.underscore.humanize.downcase 

Date le tue esigenze, probabilmente è quello che farei … Penso che sia pulito, semplice e rimarrà aggiornato nelle versioni future di Rails e Ruby.

Aggiornamento: dgilperez ha sottolineato che parameterize accetta un argomento separatore, quindi "anything".parameterize(" ") (deprecato) o "anything".parameterize(separator: " ") è più breve e più pulito.

Converti il ​​testo nel modulo di normalizzazione D, rimuovi tutti i punti di codice con il contrassegno di spaziatura non di categoria Unicode (Mn) e riconvertilo nel modulo di normalizzazione C. Questo eliminerà tutti i segni diacritici e il problema verrà ridotto a una ricerca non sensibile al maiuscolo / minuscolo.

Vedere http://www.siao2.com/2005/02/19/376617.aspx e http://www.siao2.com/2007/05/14/2629747.aspx per i dettagli.

La chiave è usare due colonne nel tuo database: canonical_text e original_text . Utilizza original_text per display e canonical_text per le ricerche. In questo modo, se un utente cerca “Visual Cafe”, vede il risultato “Visual Café”. Se vuole davvero un object diverso chiamato “Visual Cafe”, può essere salvato separatamente.

Per ottenere i caratteri canonical_text in un file sorgente di Ruby 1.8, fai qualcosa di simile a questo:

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

Probabilmente vuoi la decomposizione Unicode (“NFD”). Dopo aver decomposto la stringa, basta filtrare tutto non in [A-Za-z]. æ si decomporrà in “ae”, ã in “a ~” (circa – il segno diacritico diventerà un carattere separato), quindi il filtro lascia una ragionevole approssimazione.

Per chiunque stia leggendo questo volendo rimuovere tutti i caratteri non ascii questo potrebbe essere utile, ho usato il primo esempio con successo.

Ho avuto problemi nel trovare la soluzione foo.mb_chars.normalize (: kd) .gsub (/ [^ \ x00- \ x7F] / n, ”). Downcase.to_s per funzionare. Non sto usando Rails e c’è stato qualche conflitto con le mie versioni di supporto / ruby che non sono riuscito a ottenere in fondo.

Usare la gem ruby-unf sembra essere un buon sostituto:

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

Per quanto posso dire questo fa la stessa cosa di .mb_chars.normalize (: kd). È corretto? Grazie!

lol .. ho appena provato questo .. e sta funzionando .. iam ancora non so bene perché .. ma quando uso questo 4 linee di codice:

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

rimuove automaticamente qualsiasi accento dai nomi dei file .. che stavo cercando di rimuovere (accento dai nomi dei file e rinominarli) spero che sia stato d’aiuto 🙂