Как определить некоторые символы Unicode в строке в Ruby?
Учитывая строку в Ruby 1.8.7 (без удивительного движка регулярных выражений Oniguruma, поддерживающего свойства Unicode с помощью \p {}), я хотел бы определить, содержит ли строка одну или несколько китайских, японских или Корейские персонажи; то есть.
class String
def contains_cjk?
...
end
end
>> '日本語'.contains_cjk?
=> true
>> '광고 프로그램'.contains_cjk?
=> true
>> '艾弗森将退出篮坛'.contains_cjk?
=> true
>> 'Watashi ha bakana gaijin desu.'.contains_cjk?
=> false
Я подозреваю, что это сработает до того, что если какой-либо из символов в строке находится в Unihan CJKV Unicode блокирует, но я подумал, что стоит спросить, знает ли кто-нибудь о существующем решении в Ruby.
Ответы
Ответ 1
(ruby 1.9.2)
#encoding: UTF-8
class String
def contains_cjk?
!!(self =~ /\p{Han}|\p{Katakana}|\p{Hiragana}|\p{Hangul}/)
end
end
strings= ['日本', '광고 프로그램', '艾弗森将退出篮坛', 'Watashi ha bakana gaijin desu.']
strings.each{|s| puts s.contains_cjk?}
#true
#true
#true
#false
\ p {} соответствует символам Unicode script.
Поддерживаются следующие сценарии: арабский, армянский, балийский, бенгальский, бопофофо, брайлевский, бугийский, бухидский, канадский, аригийский, карийский, чамский, черокинский, общий, коптский, клинописный, кипрский, кириллический, дезерет, деванагари, эфиопский, грузинский, глаголицкий, Готические, Греческие, Гуджарати, Гурмухи, Хань, Хангул, Хануно, Иврит, Хирагана, Наследственные, Каннада, Катакана, Кайа_Ли, Харошти, Кхмер, Лао, Латынь, Лепча, Лимбу, Линейр_Б, Ликийская, Лидийская, Малаялам, Монголия, Мьянма, New_Tai_Lue, Nko, Ogham, Ol_Chiki, Old_Italic, Old_Persian, Oriya, Osmanya, Phags_Pa, Phoenician, Rejang, Runic, Saurashtra, Shavian, Sinhala, Sundanese, Syloti_Nagri, Syriac, Tagalog, Tagbanwa, Tai_Le, Tamil, Telugu, Thaana, Thai, Тибетский, Тифинагский, Угаритский, Вайский и Йи.
Ого. Источник Ruby Regexp.
Ответ 2
Учитывая мое ограничение Ruby 1.8.7, это лучшее, что я мог сделать:
class String
CJKV_RANGES = [
(0xe2ba80..0xe2bbbf),
(0xe2bfb0..0xe2bfbf),
(0xe38080..0xe380bf),
(0xe38180..0xe383bf),
(0xe38480..0xe386bf),
(0xe38780..0xe387bf),
(0xe38880..0xe38bbf),
(0xe38c80..0xe38fbf),
(0xe39080..0xe4b6bf),
(0xe4b780..0xe4b7bf),
(0xe4b880..0xe9bfbf),
(0xea8080..0xea98bf),
(0xeaa080..0xeaaebf),
(0xeaaf80..0xefbfbf),
]
def contains_cjkv?
each_char do |ch|
return true if CJKV_RANGES.any? {|range| range.member? ch.unpack('H*').first.hex }
end
false
end
end
strings = ['日本', '광고 프로그램', '艾弗森将退出篮坛', 'Watashi ha bakana gaijin desu.']
strings.each {|s| puts s.contains_cjkv? }
#true
#true
#true
#false
Довольно взломанный, но он работает. На самом деле он также обнаруживает множество индикационных скриптов, поэтому его, вероятно, действительно следует называть contains_asian?
Может быть, я должен это сделать для других бедных хакеров I18N, застрявших с Ruby 1.8.
Ответ 3
Я написал небольшую жемчужину, которая упаковывает подход в steenslag выше:
https://github.com/jpatokal/script_detector
Он также может нанести удар по дифференциации японского, корейского, упрощенного китайского и традиционного китайского языка, хотя из-за сложностей объединения Хан он работает только с большими плитками текста.
Ответ 4
Решение Ruby 1.8 на основе этого кода и используя API из решения Josh Glover в этом потоке:
class String
CJKV_RANGES = [
(0x4E00..0x9FFF),
(0x3400..0x4DBF),
(0x20000..0x2A6DF),
(0x2A700..0x2B73F),
]
def contains_cjkv?
unpack("U*").any? { |char|
CJKV_RANGES.any? { |range| range.member?(char) }
}
end
end