2011-01-13 23 views
16

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. caracteres; es decir,¿Cómo puedo detectar ciertos caracteres Unicode en una cadena en Ruby?

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 reducen a ver si alguno de los caracteres de la cadena están en la Unihan CJKV Unicode blocks, pero pensé que valía la pena preguntar si alguien sabe de una solución existente en Ruby.

+0

¿Está utilizando la versión 1.9 de Ruby, o simplemente una versión más antigua y sin un buen soporte Unicode expresiones regulares? Si está utilizando 1.9, debe tener acceso a (algunas) propiedades Unicode, como '\ p {InCJKUnifiedIdeographs}' o incluso '\ p {Han}'. – tchrist

+0

1.8.7 sin Oniguruma; actualizado la pregunta. –

Respuesta

39

(rubí 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 escritura Unicode de un personaje.
Se admiten los siguientes scripts: á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, Glagolitic, 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, ugarítico, vai y yi.

Wow. Ruby Regexp source.

+0

Esto definitivamente funciona en Ruby 1.9 o Ruby 1.8 con el motor Oniguruma regex. Estoy usando 1.8.7 sin Oniguruma, trágicamente. :( Gran solución, aunque no me ayuda en este caso particular. –

+2

Tuve que agregar '# codificación: UTF-8' al principio del archivo para que esto funcione. De lo contrario, obtuve una propiedad de carácter no válido nombre error. – Morrowless

+1

Tiene más sentido hacer '[p {Han} \ p {Katakana} \ p {Hiragana} \ p {Hangul}]'. – tchrist

9

dado mi restricción de Ruby 1.8.7, esto es lo mejor que podía 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.

+0

Creo que otros pueden encontrarlo útil. – Geo

+0

Tengo un proyecto bloqueado en 1.8, también. Esta solución no me funcionó, pero adapté una solución de otro subproceso de desbordamiento de pila: vea mi respuesta aquí. –

1

He escrito una pequeña joya que empaqueta el enfoque en la respuesta de steenslag arriba:

https://github.com/jpatokal/script_detector

También puede tomar una puñalada en la diferenciación entre el 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.

0

Rubí 1,8 solución basada en this code y utilizar la API de la solución de Josh Glover en este tema:

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 
Cuestiones relacionadas