루비에서 악센트 부호가있는 라틴 문자를 어떻게 바꾸나요?
필드 가있는 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를 사용하지 않기 때문에 이러한 유니 코드 리터럴을 코드에 넣을 수 없습니다. 실제 정규식은 훨씬 더보기 흉해 보일 것입니다.
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!"
이 접근 방식을 많이 시도했지만 이러한 요구 사항 중 하나 또는 여러 가지를 달성하지 못했습니다.
- 공간 존중
- 'ñ'문자 존중
- 사례 존중 (원래 질문에 대한 요구 사항은 아니지만 문자열을 소문자 로 옮기는 것이 어렵지 않다는 것을 알고 있습니다 )
이것은 :
# coding: utf-8
string.tr(
"ÀÁÂÃÄÅàáâãäåĀāĂ㥹ÇçĆćĈĉĊċČčÐðĎďĐđÈÉÊËèéêëĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħÌÍÎÏìíîïĨĩĪīĬĭĮįİıĴĵĶķĸĹĺĻļĽľĿŀŁłÑñŃńŅņŇňʼnŊŋÒÓÔÕÖØòóôõöøŌōŎŏŐőŔŕŖŗŘřŚśŜŝŞşŠšſŢţŤťŦŧÙÚÛÜùúûüŨũŪūŬŭŮůŰűŲųŴŵÝýÿŶŷŸŹźŻżŽž",
"AAAAAAaaaaaaAaAaAaCcCcCcCcCcDdDdDdEEEEeeeeEeEeEeEeEeGgGgGgGgHhHhIIIIiiiiIiIiIiIiIiJjKkkLlLlLlLlLlNnNnNnNnnNnOOOOOOooooooOoOoOoRrRrRrSsSsSsSssTtTtTtUUUUuuuuUuUuUuUuUuUuWwYyyYyYZzZzZz"
)
'ñ'문자를 존중하기 위해 문자 목록을 약간 수정해야하지만 쉬운 일입니다.
내 대답 : String # parameterize 메서드 :
"Le cœur de la crémiére".parameterize
=> "le-coeur-de-la-cremiere"
비철도 프로그램의 경우 :
activesupport를 설치하십시오 gem install activesupport
.
require 'active_support/inflector'
"a&]'s--3\014\xC2àáâã3D".parameterize
# => "a-s-3-3d"
나는 당신이 정말로 그 길로 가야 할 것이 아닐 것이라고 생각합니다. 이런 종류의 문자가있는 시장을 위해 개발하는 경우 사용자는 아마도 당신이 일종의 ... 핍 이라고 생각할 것입니다 . 'å'는 사용자에게 어떤 의미에서도 'a'에 가깝지 않기 때문입니다. 다른 길을 가고 비 ASCII 방식으로 검색하는 것에 대해 읽어보십시오. 이것은 누군가가 유니 코드와 데이터 정렬을 발명 한 경우 중 하나 일뿐 입니다.
매우 늦은 PS :
http://www.w3.org/International/wiki/Case_folding http://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 및 Ruby 버전에서 최신 상태로 유지 될 것이라고 생각합니다.
업데이트 : dgilperez는 parameterize
구분자 인수 를 취하므로 "anything".parameterize(" ")
(사용되지 않음) 또는 "anything".parameterize(separator: " ")
더 짧고 깔끔하다고 지적했습니다 .
Convert the text to normalization form D, remove all codepoints with unicode category non spacing mark (Mn), and convert it back to normalization form C. This will strip all diacritics, and your problem is reduced to a case insensitive search.
See http://www.siao2.com/2005/02/19/376617.aspx and http://www.siao2.com/2007/05/14/2629747.aspx for details.
The key is to use two columns in your database: canonical_text
and original_text
. Use original_text
for display and canonical_text
for searches. That way, if a user searches for "Visual Cafe," she sees the "Visual Café" result. If she really wants a different item called "Visual Cafe," it can be saved separately.
To get the canonical_text characters in a Ruby 1.8 source file, do something like this:
register_replacement([0x008A].pack('U'), 'S')
You probably want Unicode decomposition ("NFD"). After decomposing the string, just filter out anything not in [A-Za-z]. æ will decompose to "ae", ã to "a~" (approximately - the diacritical will become a separate character) so the filtering leaves a reasonable approximation.
iconv:
http://groups.google.com/group/ruby-talk-google/browse_frm/thread/8064dcac15d688ce?
=============
a perl module which i can't understand:
http://www.ahinea.com/en/tech/accented-translate.html
============
brute force (there's a lot of htose critters!:
http://projects.jkraemer.net/acts_as_ferret/wiki#UTF-8support
http://snippets.dzone.com/posts/show/2384
For anyone reading this wanting to strip all non-ascii characters this might be useful, I used the first example successfully.
I had problems getting the foo.mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/n,'').downcase.to_s solution to work. I'm not using Rails and there was some conflict with my activesupport/ruby versions that I couldn't get to the bottom of.
Using the ruby-unf gem seems to be a good substitute:
require 'unf'
foo.to_nfd.gsub(/[^\x00-\x7F]/n,'').downcase
As far as I can tell this does the same thing as .mb_chars.normalize(:kd). Is this correct? Thanks!
If you are using PostgreSQL => 9.4 as your DB adapter, maybe you could add in a migration it's "unaccent" extension that I think does what you want, like this:
def self.up
enable_extension "unaccent" # No falla si ya existe
end
In order to test, in the console:
2.3.1 :045 > ActiveRecord::Base.connection.execute("SELECT unaccent('unaccent', 'àáâãäåÁÄ')").first
=> {"unaccent"=>"aaaaaaAA"}
Notice there is case sensitive up to now.
Then, maybe use it in a scope, like:
scope :with_canonical_name, -> (name) {
where("unaccent(foos.name) iLIKE unaccent('#{name}')")
}
The iLIKE operator makes the search case insensitive. There is another approach, using citext data type. Here is a discussion about this two approaches. Notice also that use of PosgreSQL's lower() function is not recommended.
This will save you some DB space, since you will no longer require the cannonical_name field, and perhaps make your model simpler, at the cost of some extra processing in each query, in an amount depending of whether you are using iLIKE or citext, and your dataset.
If you are using MySQL maybe you can use this simple solution, but I have not tested it.
lol.. i just tryed this.. and it is working.. iam still not pretty sure why.. but when i use this 4 lines of code:
- str = str.gsub(/[^a-zA-Z0-9 ]/,"")
- str = str.gsub(/[ ]+/," ")
- str = str.gsub(/ /,"-")
- str = str.downcase
it automaticly removes any accent from filenames.. which i was trying to remove(accent from filenames and renaming them than) hope it helped :)
참고URL : https://stackoverflow.com/questions/225471/how-do-i-replace-accented-latin-characters-in-ruby
'IT TIP' 카테고리의 다른 글
문자열 내에서 URL을 찾기위한 정규식 (0) | 2020.11.02 |
---|---|
gem install pg --with-pg-config 작동, 번들 실패 (0) | 2020.11.02 |
문화에 관계없이 소수점 이하 자릿수 찾기 (0) | 2020.11.02 |
버튼 그룹의 너비를 100 %로 설정하고 버튼의 너비를 같게 만드시겠습니까? (0) | 2020.11.02 |
복잡한 C 선언 (0) | 2020.11.02 |