Ich habe ein ActiveRecord
Modell Foo
, das ein name
Feld hat. Ich möchte, dass Benutzer nach Namen suchen können, aber ich möchte, dass bei der Suche Groß- und Kleinschreibung und Akzente ignoriert werden. Daher speichere ich auch ein canonical_name
Feld, nach dem gesucht werden soll:
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
Ich muss das "Etwas hier" ausfüllen, um die akzentuierten Zeichen zu ersetzen. Gibt es etwas besseres als
x.downcase.gsub(/[àáâãäå]/,'a').gsub(/æ/,'ae').gsub(/ç/, 'c').gsub(/[èéêë]/,'e')....
Und da ich nicht auf Ruby 1.9 bin, kann ich diese Unicode-Literale nicht in meinen Code einfügen. Die tatsächlichen regulären Ausdrücke sehen viel hässlicher aus.
ruby-on-rails
ruby
activerecord
unicode
utf-8
James A. Rosen
quelle
quelle
name
undcanonical_name
. Ich befürworte nicht, die tatsächlichen Daten zu verwerfen, sondern lediglich eine Möglichkeit zu schaffen, sie ohne diakritische Zeichen zu durchsuchen, die Benutzer aller Sprachen häufig weglassen.Antworten:
Rails verfügt bereits über eine integrierte Funktion zum Normalisieren. Sie müssen diese nur verwenden, um Ihre Zeichenfolge zu normalisieren, um KD zu bilden, und dann die anderen Zeichen (dh Akzentzeichen) wie folgt entfernen:
>> "àáâãäå".mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/n,'').downcase.to_s => "aaaaaa"
quelle
activesupport
, aber nachdem ich es verlangt habe, bekomme ich immer noch einNoMethodError
fürnormalize
. Wissen Sie, was ich benötigen muss?mb_chars
wie Christian machen.foo.mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/n,'').to_s.split
ActiveSupport::Inflector.transliterate
(erfordert Rails 2.2.1+ und Ruby 1.9 oder 1.8.7)Beispiel:
>> ActiveSupport::Inflector.transliterate("àáâãäå").to_s => "aaaaaa"
quelle
require 'active_support/inflector'
in Nicht-Rails-Projekt (siehe meine Antwort unten)Besser noch ist es, I18n zu verwenden:
1.9.3-p392 :001 > require "i18n" => false 1.9.3-p392 :002 > I18n.transliterate("Olá Mundo!") => "Ola Mundo!"
quelle
cannot load such file -- i18n
nursudo gem install i18n
.:en is not a valid locale (I18n::InvalidLocale)
bis ich hinzugefügt habeI18n.available_locales = [:en]
. Dies ersetzt auch Nicht-ASCII-Zeichen, die keine lateinischen Buchstaben sind, durch diakritische Zeichen mit Fragezeichen, sodass beispielsweiseruby -ri18n -ne'I18n.available_locales=[:en];puts I18n.transliterate$_'<<<Дあ☆
gedruckt wird???
.Ich habe viele dieser Ansätze ausprobiert, aber sie haben eine oder mehrere dieser Anforderungen nicht erfüllt:
War das:
# coding: utf-8 string.tr( "ÀÁÂÃÄÅàáâãäåĀāĂ㥹ÇçĆćĈĉĊċČčÐðĎďĐđÈÉÊËèéêëĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħÌÍÎÏìíîïĨĩĪīĬĭĮįİıĴĵĶķĸĹĺĻļĽľĿŀŁłÑñŃńŅņŇňʼnŊŋÒÓÔÕÖØòóôõöøŌōŎŏŐőŔŕŖŗŘřŚśŜŝŞşŠšſŢţŤťŦŧÙÚÛÜùúûüŨũŪūŬŭŮůŰűŲųŴŵÝýÿŶŷŸŹźŻżŽž", "AAAAAAaaaaaaAaAaAaCcCcCcCcCcDdDdDdEEEEeeeeEeEeEeEeEeGgGgGgGgHhHhIIIIiiiiIiIiIiIiIiJjKkkLlLlLlLlLlNnNnNnNnnNnOOOOOOooooooOoOoOoRrRrRrSsSsSsSssTtTtTtUUUUuuuuUuUuUuUuUuUuWwYyyYyYZzZzZz" )
- http://blog.slashpoundbang.com/post/12938588984/remove-all-accents-and-diacritics-from-string-in-ruby
Sie müssen die Zeichenliste ein wenig ändern, um das Zeichen 'ñ' zu respektieren, aber es ist eine leichte Aufgabe.
quelle
ñ
? Es scheint mir, dass es bereits in der Liste ist und mit ausgerichtet istn
.ñ
Charakter zu respektieren , möchte ich ihn NICHT in einenn
Charakter verwandeln, sondern behalten.ñ
in Ihrer Liste mit Anforderungen mit Aufzählungszeichen herauszugreifen.ñ
ist der "lateinische Kleinbuchstabe n mit Tilde" und befindet sich im erweiterten ASCII-Satz, zusammen mit vielen anderen in Ihrer Liste - siehe ascii-code.com -, während Ihre Liste eine Reihe von Zeichen enthält, die dies nicht sind im erweiterten ASCII-Satz, einschließlichĄ
undĦ
. Ich bin immer noch verwirrt darüber, warum Sie herausgegriffen habenñ
.ActiveSupport::Inflector.transliterate
scheint Ihre Anforderungen zu erfüllen, mit Ausnahme der "Retention ñ" und auch dieser Weg ist reiner Rubin, was schön ist. Leider können Sie mit Unicode seltsame Dinge tun, z. B. einen Umlaut über praktisch alle vorhergehenden Zeichen hinzufügen. Daher ist es schwierig, diesen Ansatz so umfassend zu gestalten, dass alle Situationen erfüllt werden: |Meine Antwort: die String # -Parameterisierungsmethode :
"Le cœur de la crémiére".parameterize => "le-coeur-de-la-cremiere"
Für Nicht-Rails-Programme:
Installiere activesupport:
gem install activesupport
dann:require 'active_support/inflector' "a&]'s--3\014\xC2àáâã3D".parameterize # => "a-s-3-3d"
quelle
`method`
) hilft beim Lesen des Teils des Kommentars. Und um Ihre Frage zu beantworten,"Le cœur de la crémiére".parameterize
ist das beste UTF-8 zu ASCII für URLs, es ist super nett und süßIch denke, dass Sie vielleicht nicht wirklich wissen, was Sie auf diesem Weg tun sollen. Wenn Sie sich für einen Markt mit solchen Buchstaben entwickeln, werden Ihre Benutzer wahrscheinlich denken, dass Sie eine Art ... Pip sind . Weil 'å' für einen Benutzer nicht einmal in der Nähe von 'a' liegt. Nehmen Sie einen anderen Weg und informieren Sie sich über die Suche auf nicht-ASCII-Weise. Dies ist nur einer dieser Fälle, in denen jemand Unicode und Kollation erfunden hat .
Eine sehr späte PS :
http://www.w3.org/International/wiki/Case_folding http://www.w3.org/TR/charmod-norm/#sec-WhyNormalization
Außerdem habe ich keine Ahnung, wie der Link zur Sortierung zu einer MSDN-Seite führt, aber ich lasse ihn dort. Es sollte http://www.unicode.org/reports/tr10/ gewesen sein.
quelle
Zerlegen Sie die Zeichenfolge und entfernen Sie nicht voneinander entfernte Markierungen .
irb -ractive_support/all > "àáâãäå".mb_chars.normalize(:kd).gsub(/\p{Mn}/, '') aaaaaa
Möglicherweise benötigen Sie dies auch, wenn Sie es in einer .rb-Datei verwenden.
# coding: utf-8
Der
normalize(:kd)
Teil hier teilt diakritische Zeichen nach Möglichkeit auf (z. B. das einzelne Zeichen "n mit Tilda" wird in ein n aufgeteilt, gefolgt von einem kombinierten diakritischen Tilda-Zeichen), und dergsub
Teil entfernt dann alle diakritischen Zeichen.quelle
I18n.transliterate('日本語') #=> "???"
) und vollständig'日本語'.parameterize #=> ""
. Diese Antwort entspricht am ehesten meinen Anforderungen, nämlich in der Lage zu sein, verschiedene Datensätze zu Titeln / Autoren ungefähr abzugleichen.'日本語 àáâãäå'.unicode_normalize(:nfkd).gsub(/\p{Mn}/, '') #=> "日本語 aaaaaa"
Dies setzt voraus, dass Sie Rails verwenden.
"anything".parameterize.underscore.humanize.downcase
Angesichts Ihrer Anforderungen würde ich dies wahrscheinlich tun ... Ich denke, es ist ordentlich, einfach und wird in zukünftigen Versionen von Rails und Ruby auf dem neuesten Stand bleiben.
Update: dgilperez wies darauf hin, dass
parameterize
ein Trennzeichen Argument, also"anything".parameterize(" ")
(veraltet) oder"anything".parameterize(separator: " ")
kürzer und sauberer ist.quelle
"anything".parameterize(" ")
kürzer?.parameterize(" ")
ist kürzer, aber es fällt alles runter. Und ich habe keine Möglichkeit gefunden, daspreserve_case
Argument an den Ausdruck anzuhängen .I18n.transliterate
ist am effizientesten und effektivsten.Konvertieren Sie den Text in das Normalisierungsformular D, entfernen Sie alle Codepunkte mit der Unicode-Kategorie ohne Abstand (Mn) und konvertieren Sie ihn zurück in das Normalisierungsformular C. Dadurch werden alle diakritischen Zeichen entfernt, und Ihr Problem wird auf eine Suche ohne Berücksichtigung der Groß- und Kleinschreibung reduziert.
Weitere Informationen finden Sie unter http://www.siao2.com/2005/02/19/376617.aspx und http://www.siao2.com/2007/05/14/2629747.aspx .
quelle
Der Schlüssel besteht darin, zwei Spalten in Ihrer Datenbank zu verwenden:
canonical_text
undoriginal_text
. Zuroriginal_text
Anzeige undcanonical_text
Suche verwenden. Auf diese Weise sieht ein Benutzer, wenn er nach "Visual Cafe" sucht, das Ergebnis "Visual Café". Wenn sie wirklich einen anderen Gegenstand namens "Visual Cafe" möchte, kann dieser separat gespeichert werden.Gehen Sie folgendermaßen vor, um die Zeichen canonical_text in einer Ruby 1.8-Quelldatei abzurufen:
register_replacement([0x008A].pack('U'), 'S')
quelle
Sie möchten wahrscheinlich eine Unicode-Zerlegung ("NFD"). Filtern Sie nach dem Zerlegen des Strings einfach alles heraus, was nicht in [A-Za-z] enthalten ist. æ zerfällt in "ae", ã in "a ~" (ungefähr - das diakritische Zeichen wird zu einem separaten Zeichen), sodass die Filterung eine vernünftige Annäherung hinterlässt.
quelle
iconv:
http://groups.google.com/group/ruby-talk-google/browse_frm/thread/8064dcac15d688ce ?
=============
Ein Perl-Modul, das ich nicht verstehen kann:
http://www.ahinea.com/de/tech/accented-translate.html
============
Brute Force (es gibt viele Htose Critters!:
http://projects.jkraemer.net/acts_as_ferret/wiki#UTF-8support
http://snippets.dzone.com/posts/show/2384
quelle
Für alle , die dies lesen , alle nicht-ASCII - Zeichen abzustreifen will dies nützlich sein könnte, habe ich das erste Beispiel erfolgreich.
quelle
Ich hatte Probleme, die Lösung foo.mb_chars.normalize (: kd) .gsub (/ [^ \ x00- \ x7F] / n, ''). Downcase.to_s zum Laufen zu bringen. Ich benutze keine Rails und es gab einen Konflikt mit meinen aktiven Support- / Ruby-Versionen, dem ich nicht auf den Grund gehen konnte.
Die Verwendung des rubinroten Edelsteins scheint ein guter Ersatz zu sein:
require 'unf' foo.to_nfd.gsub(/[^\x00-\x7F]/n,'').downcase
Soweit ich das beurteilen kann, funktioniert dies genauso wie .mb_chars.normalize (: kd). Ist das richtig? Vielen Dank!
quelle
Wenn Sie PostgreSQL => 9.4 als DB-Adapter verwenden, können Sie bei einer Migration möglicherweise die Erweiterung "inaccent" hinzufügen , die meiner Meinung nach das tut, was Sie wollen, wie folgt:
def self.up enable_extension "unaccent" # No falla si ya existe end
Zum Testen in der Konsole:
2.3.1 :045 > ActiveRecord::Base.connection.execute("SELECT unaccent('unaccent', 'àáâãäåÁÄ')").first => {"unaccent"=>"aaaaaaAA"}
Beachten Sie, dass bisher zwischen Groß- und Kleinschreibung unterschieden wird.
Verwenden Sie es dann möglicherweise in einem Bereich wie:
scope :with_canonical_name, -> (name) { where("unaccent(foos.name) iLIKE unaccent('#{name}')") }
Der iLIKE-Operator macht die Suche unabhängig von Groß- und Kleinschreibung. Es gibt einen anderen Ansatz, bei dem der Datentyp citext verwendet wird. Hier ist eine Diskussion über diese beiden Ansätze. Beachten Sie auch, dass die Verwendung der Funktion lower () von PosgreSQL nicht empfohlen wird .
Dies spart Ihnen etwas DB-Speicherplatz, da Sie das Feld cannonical_name nicht mehr benötigen, und vereinfacht möglicherweise Ihr Modell auf Kosten einer zusätzlichen Verarbeitung in jeder Abfrage in einer Menge, die davon abhängt, ob Sie iLIKE oder citext verwenden, und Ihr Datensatz.
Wenn Sie MySQL verwenden , können Sie vielleicht diese einfache Lösung verwenden , aber ich habe sie nicht getestet.
quelle
lol .. ich habe es gerade versucht .. und es funktioniert .. ich bin mir immer noch nicht ganz sicher warum .. aber wenn ich diese 4 Codezeilen benutze:
Es entfernt automatisch jeden Akzent aus Dateinamen. Ich habe versucht zu entfernen (Akzent aus Dateinamen und umbenennen als). Ich hoffe, es hat geholfen :)
quelle