regexp - ¿Cómo puedo detectar ciertos caracteres Unicode en una cadena en Ruby?
regexp match ruby (4)
Dada una cadena en Ruby 1.8.7 (sin el asombroso motor de expresión regular Oniguruma que admite las propiedades Unicode con / p {}), me gustaría poder determinar si la cadena contiene uno o más caracteres chinos, japoneses o coreanos; es decir
class String
def contains_cjk?
...
end
end
>> ''日本語''.contains_cjk?
=> true
>> ''광고 프로그램''.contains_cjk?
=> true
>> ''艾弗森将退出篮坛''.contains_cjk?
=> true
>> ''Watashi ha bakana gaijin desu.''.contains_cjk?
=> false
Sospecho que esto se reducirá a ver si alguno de los caracteres de la cadena está en los bloques Unicode CJKV Unicode , pero pensé que valía la pena preguntar si alguien sabe de una solución existente en Ruby.
Dada mi restricción de Ruby 1.8.7, esto es lo mejor que puedo hacer:
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
Bastante hacktacular, pero funciona. En realidad, también detecta una variedad de scripts de Indic, por lo que probablemente debería llamarse contains_asian.
Tal vez debería joder esto para otros hackers I18N pobres atrapados con Ruby 1.8.
He escrito una pequeña joya que empaqueta el enfoque en la respuesta de steenslag anterior:
https://github.com/jpatokal/script_detector
También puede ser difícil diferenciar entre japonés, coreano, chino simplificado y chino tradicional, aunque debido a las complejidades de la unificación de Han, solo funciona de manera confiable con grandes bloques de texto.
(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 {} coincide con la secuencia de comandos Unicode de un personaje.
Los siguientes guiones son compatibles: árabe, armenio, balinés, bengalí, Bopomofo, Braille, Buginese, Buhid, Canadian_Aboriginal, Carian, Cham, Cherokee, común, copto, cuneiforme, chipriota, cirílico, Deseret, Devanagari, etíope, georgiano, glagolítico, Gótico, Griego, Gujarati, Gurmukhi, Han, Hangul, Hanunoo, Hebreo, Hiragana, Heredado, Kannada, Katakana, Kayah_Li, Kharoshthi, Khmer, Lao, Latín, Lepcha, Limbu, Linear_B, Licio, Lidio, Malayalam, Mongol, Myanmar, 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, tailandés, Tibetano, Tifinagh, Ugaritic, Vai y Yi.
Guau. Fuente Ruby Regexp .
Solución de Ruby 1.8 basada en este código y usando la API de la solución de Josh Glover en este hilo:
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