2011-01-13 17 views
16

Biorąc ciąg w Ruby 1.8.7 (bez niesamowitego silnika wyrażeń regularnych Oniguruma, który obsługuje właściwości Unicode z \ p {}), chciałbym móc określić, czy ciąg zawiera co najmniej jeden chiński, japoński lub koreański postacie; tjJak wykryć niektóre znaki Unicode w łańcuchu w 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 

Podejrzewam, że to będzie sprowadzają się do zobaczyć, czy każdy ze znaków w łańcuchu są w Unihan CJKV Unicode blocks, ale pomyślałem, że warto było pytać, czy ktoś wie istniejącego roztworu w Ruby.

+0

używasz wersji 1.9 Ruby, czy tylko wersję bez dobrego wsparcia regex Unicode? Jeśli używasz 1.9, powinieneś mieć dostęp do (niektórych) właściwości Unicode, takich jak '\ p {InCJKUnifiedIdeographs}', a może nawet '\ p {Han}'. – tchrist

+0

1.8.7 bez Oniguruma; zaktualizował pytanie. –

Odpowiedz

39

(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 {} odpowiada skrypt znak Unicode. Obsługiwane są następujące skrypty: arabski, ormiański, balijski, bengalski, bopomofo, brajl, bugiński, buhid, kanadyjski, aryjski, karyjski, czam, czirokez, pospolity, koptyjski, klinowy, cypryjski, deseret, dewanagari, etiopski, gruziński, Głagolicki, gotycki, grecki, gudżarati, gurmukhi, han, hangul, hanunoo, hebrajski, hiragana, odziedziczony, kannada, katakana, kajahi, kharoszthi, khmerski, łaciński, łaciński, lepcha, limbu, liniowy, bierski, lydeński, malajalam, mongolski, Myanmar, New_Tai_Lue, Nko, Ogham, Ol_Chiki, Old_Italic, Old_Persian, Oriya, Osmanya, Phags_Pa, Phoenician, Rejang, Runica, Saurashtra, Shavian, Sinhala, Sundanese, Syloti_Nagri, Syriac, Tagalog, Tagbanwa, Tai_Le, Tamil, Telugu, Thaana, Tajski, tybetański, Tifinagh, Ugaritic, Vai i Yi.

Wow. Ruby Regexp source.

+0

To z pewnością działa w Rubim 1.9 lub Ruby 1.8 z silnikiem regex Oniguruma. Używam 1.8.7 bez Oniguruma, tragicznie. :( Świetne rozwiązanie, nawet jeśli nie pomaga mi to w tym konkretnym przypadku –

+2

Musiałem dodać "# encoding: UTF-8" na górze pliku, aby to zadziałało. W przeciwnym razie dostałem nieprawidłową właściwość znaku nazwa błędu: – Morrowless

+1

Bardziej sensowne jest robienie '[p {Han} \ p {Katakana} \ p {Hiragana} \ p {Hangul}]'. – tchrist

9

Ruby 1.8.7 Biorąc pod uwagę moje ograniczenia, to najlepsze co mogłem zrobić:

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 

Dość hacktacular, ale to działa. W rzeczywistości wykrywa również różne skrypty indeksu, więc prawdopodobnie powinno się nazywać je contains_asian?

Może powinienem to docenić dla innych biednych hakerów I18N utkniętych z Ruby 1.8.

+0

Myślę, że inni mogą uznać to za pomocne. – Geo

+0

Mam projekt utknął również na 1.8. To rozwiązanie nie działa dla mnie, ale zaadaptowałem rozwiązanie z innego wątku Stack Overflow - zobacz moją odpowiedź tutaj. –

1

Pisałem trochę klejnot, który paczek podejścia w odpowiedzi steenslag jest powyżej:

https://github.com/jpatokal/script_detector

Można również wziąć ukłucie w różnicowaniu pomiędzy japoński, koreański, chiński uproszczony i tradycyjny chiński, choć ze względu na złożoność unifikacji Han działa tylko niezawodnie przy dużych płytach tekstu.

0

Ruby 1.8 rozwiązanie oparte na this code i za pomocą interfejsu API z roztworu Josh Glovera w tym wątku:

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 
Powiązane problemy