ActiveRecord
フィールドを持つFoo
モデル、name
があります。ユーザーが名前で検索できるようにしたいのですが、大文字と小文字のアクセントを無視して検索したいです。したがって、検索対象のcanonical_name
フィールドも格納しています。
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
アクセント記号付きの文字を置き換えるには、「ここに何か」を入力する必要があります。より良いものはありますか
x.downcase.gsub(/[àáâãäå]/,'a').gsub(/æ/,'ae').gsub(/ç/, 'c').gsub(/[èéêë]/,'e')....
そして、その点については、私はRuby 1.9ではないので、これらのUnicodeリテラルをコードに入れることはできません。実際の正規表現はずっと見苦しくなります。
Railsにはすでに正規化のためのビルトインがあり、これを使用して文字列を正規化してKDを形成し、次に他の文字(つまりアクセント記号)を削除する必要があります:
>> "àáâãäå".mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/n,'').downcase.to_s
=> "aaaaaa"
_ActiveSupport::Inflector.transliterate
_(Rails 2.2.1+およびRuby 1.9または1.8.7)が必要です)
例:
>> ActiveSupport::Inflector.transliterate("àáâãäå").to_s => "aaaaaa"
さらに良いのは、I18nを使用することです。
1.9.3-p392 :001 > require "i18n"
=> false
1.9.3-p392 :002 > I18n.transliterate("Olá Mundo!")
=> "Ola Mundo!"
私はこのアプローチを多数試しましたが、これらの要件の1つまたはいくつかを達成していませんでした。
これがされています:
# coding: utf-8
string.tr(
"ÀÁÂÃÄÅàáâãäåĀāĂ㥹ÇçĆćĈĉĊċČčÐðĎďĐđÈÉÊËèéêëĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħÌÍÎÏìíîïĨĩĪīĬĭĮįİıĴĵĶķĸĹĺĻļĽľĿŀŁłÑñŃńŅņŇňʼnŊŋÒÓÔÕÖØòóôõöøŌōŎŏŐőŔŕŖŗŘřŚśŜŝŞşŠšſŢţŤťŦŧÙÚÛÜùúûüŨũŪūŬŭŮůŰűŲųŴŵÝýÿŶŷŸŹźŻżŽž",
"AAAAAAaaaaaaAaAaAaCcCcCcCcCcDdDdDdEEEEeeeeEeEeEeEeEeGgGgGgGgHhHhIIIIiiiiIiIiIiIiIiJjKkkLlLlLlLlLlNnNnNnNnnNnOOOOOOooooooOoOoOoRrRrRrSsSsSsSssTtTtTtUUUUuuuuUuUuUuUuUuUuWwYyyYyYZzZzZz"
)
「ñ」文字を尊重するには、文字リストを少し修正する必要がありますが、簡単な作業です。
私の答え: String#parameterize メソッド:
"Le cœur de la crémiére".parameterize
=> "le-coeur-de-la-cremiere"
非Railsプログラムの場合:
Activesupportのインストール:gem install activesupport
その後:
require 'active_support/inflector'
"a&]'s--3\014\xC2àáâã3D".parameterize
# => "a-s-3-3d"
私はあなたがたぶんその道をどう進むべきか本当にわからないと思います。このような種類の文字を含む市場向けに開発している場合、ユーザーはおそらく...pipのように思うでしょう。ユーザーにとって「å」は「a」に近い意味でもないからです。別の道を進み、非ASCIIの方法での検索について読んでください。これは、誰かがユニコードと 照合 を発明したケースの1つにすぎません。
非常に遅いPS:
http://www.w3.org/International/wiki/Case_foldinghttp://www.w3.org/TR/charmod-norm/#sec-WhyNormalization
それに加えて、照合へのリンクがmsdnページに行く理想的な方法はありませんが、そこに残します。 http://www.unicode.org/reports/tr10/
文字列を分解して、 非スペースマーク を削除します。
_irb -ractive_support/all
> "àáâãäå".mb_chars.normalize(:kd).gsub(/\p{Mn}/, '')
aaaaaa
_
.rbファイルで使用する場合、これも必要になる場合があります。
_# coding: utf-8
_
ここのnormalize(:kd)
部分は、可能であれば分音記号を分割します(例:「n with tilda」単一文字はnに分割され、その後に結合分音記号チルダ文字が続きます)、そしてgsub
部分すべての発音区別文字を削除します。
これはRailsを使用することを前提としています
_"anything".parameterize.underscore.humanize.downcase
_
あなたの要件を考えると、これはおそらく私がやることです...私はそれがきちんとしていて、シンプルだと思いますRails and Ruby。
更新:dgilperezは、parameterize
がセパレーター引数を取るため、"anything".parameterize(" ")
(非推奨)または"anything".parameterize(separator: " ")
がより短く、よりクリーンであることを指摘しました。
テキストを正規化フォームDに変換し、Unicodeカテゴリーの非スペーシングマーク(Mn)を持つすべてのコードポイントを削除し、正規化フォームCに変換します。これにより、すべての発音区別符号が削除され、大文字と小文字を区別しない検索になります。
http://www.siao2.com/2005/02/19/376617.aspx および http://www.siao2.com/2007/05/14/2629747を参照してください。詳細については、aspx .
重要な点は、データベースで2つの列を使用することです:canonical_text
およびoriginal_text
。使用する original_text
表示およびcanonical_text
検索用。これにより、ユーザーが「Visual Cafe」を検索すると、「VisualCafé」の結果が表示されます。彼女がreallyで「Visual Cafe」という別のアイテムが必要な場合は、個別に保存できます。
Ruby 1.8ソースファイルのcanonical_text文字を取得するには、次のようにします。
register_replacement([0x008A].pack('U'), 'S')
おそらくUnicode分解( "NFD")が必要でしょう。文字列を分解した後、[A-Za-z]に含まれていないものをすべて除外します。 æは「ae」に、ãは「a〜」に分解されます(およそ-ダイアクリティカルマークは別の文字になります)。したがって、フィルタリングは妥当な近似を残します。
これを読んでいるすべての非ASCII文字を削除したい場合 this が役に立つかもしれません。最初の例をうまく使いました。
iconv:
http://groups.google.com/group/Ruby-talk-google/browse_frm/thread/8064dcac15d688ce ?
=============
私が理解できないPerlモジュール:
http://www.ahinea.com/en/tech/accented-translate.html
============
ブルートフォース(多数の生き物がいます!:
http://projects.jkraemer.net/acts_as_ferret/wiki#UTF-8support
Foo.mb_chars.normalize(:kd).gsub(/ [^\x00-\x7F]/n、 '')。downcase.to_sソリューションを機能させるのに問題がありました。 Railsを使用していないため、activesupport/Rubyのバージョンとの競合が発生したため、最後まで到達できませんでした。
Ruby-unf gemを使用するのは良い代替策のようです:
require 'unf'
foo.to_nfd.gsub(/[^\x00-\x7F]/n,'').downcase
私が知る限り、これは.mb_chars.normalize(:kd)と同じことを行います。これは正しいです?ありがとう!
PostgreSQLを使用している場合=> 9.4 DBアダプタとして、移行に追加することができます "unaccent" extension 私はあなたが望むことをこのように思うと思う:
def self.up
enable_extension "unaccent" # No falla si ya existe
end
テストするには、コンソールで:
2.3.1 :045 > ActiveRecord::Base.connection.execute("SELECT unaccent('unaccent', 'àáâãäåÁÄ')").first
=> {"unaccent"=>"aaaaaaAA"}
今まで大文字と小文字が区別されることに注意してください。
次に、次のようにスコープで使用します。
scope :with_canonical_name, -> (name) {
where("unaccent(foos.name) iLIKE unaccent('#{name}')")
}
ILIKE演算子は、検索で大文字と小文字を区別しません。 citext データ型を使用する別のアプローチがあります。 ここ は、この2つのアプローチに関する議論です。また、PosgreSQLのlower()関数の使用 推奨されません にも注意してください。
これにより、cannonical_nameフィールドが不要になり、おそらく各クエリで追加の処理が必要になりますが、iLIKEまたはcitextのどちらを使用しているかに応じて、モデルを単純化するため、DBスペースが節約されます。データセット。
MySQLを使用している場合は、おそらく この単純なソリューションを使用 が可能ですが、テストは行っていません。