2011-01-13 29 views
16

Cho một chuỗi trong Ruby 1.8.7 (không có công cụ biểu thức chính quy Oniguruma tuyệt vời hỗ trợ các thuộc tính Unicode với \ p {}), tôi muốn có thể xác định xem chuỗi có chứa một hoặc nhiều tiếng Trung, tiếng Nhật hay tiếng Hàn nhân vật; ví dụ:Làm thế nào tôi có thể phát hiện các ký tự Unicode nhất định trong một chuỗi trong 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 

tôi nghi ngờ rằng điều này sẽ đun sôi xuống để xem nếu bất kỳ của các nhân vật trong chuỗi đang trong Unihan CJKV Unicode blocks, nhưng tôi nghĩ đó là giá trị yêu cầu nếu có ai biết của một giải pháp hiện có trong Ruby.

+0

Bạn đang sử dụng phiên bản 1.9 của Ruby, hay chỉ là một phiên bản cũ mà không Unicode hỗ trợ regex tốt? Nếu bạn đang sử dụng 1.9, bạn sẽ có quyền truy cập vào một số thuộc tính Unicode, như '\ p {InCJKUnifiedIdeographs}' hoặc thậm chí là '\ p {Han}'. – tchrist

+0

1.8.7 không có Oniguruma; đã cập nhật câu hỏi. –

Trả lời

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 {} phù hợp với kịch bản Unicode của một nhân vật.
Các tập lệnh sau được hỗ trợ: tiếng Ả Rập, tiếng Armenia, tiếng Bali, tiếng Bengali, tiếng Bopomofo, chữ nổi, tiếng Buginese, tiếng Buhid, tiếng Canada_Aboriginal, Carian, Cham, Cherokee, Common, Coptic, Cuneiform, Cypriot, Cyrillic, Deseret, Devanagari, Ethiopic, Georgian, Glagolitic, Gothic, Hy Lạp, Gujarati, Gurmukhi, Han, Hangul, Hanunoo, Hebrew, Hiragana, Thừa kế, Kannada, Katakana, Kayah_Li, Kharoshthi, Khmer, Lào, Latin, Lepcha, Limbu, Linear_B, Lycian, Lydian, Malayalam, Mông Cổ, 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, Thái, Tây Tạng, Tifinagh, Ugaritic, Vai và Yi.

Wow. Ruby Regexp source.

+0

Điều này chắc chắn hoạt động trong Ruby 1.9, hoặc Ruby 1.8 với công cụ regex Oniguruma. Tôi đang sử dụng 1.8.7 mà không có Oniguruma, bi kịch. :( Giải pháp tuyệt vời, mặc dù nó không giúp tôi trong trường hợp cụ thể này. –

+2

Tôi phải thêm '# encoding: UTF-8' vào đầu tệp để thực hiện tác vụ này. Lỗi tên – Morrowless

+1

Làm cho ý nghĩa hơn để làm '[p {Han} \ p {Katakana} \ p {Hiragana} \ p {Hangul}]'. – tchrist

9

Do hạn chế của Ruby 1.8.7 của tôi, điều này là tốt nhất tôi có thể làm:

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 

Khá hacktacular, nhưng nó hoạt động. Nó thực sự phát hiện một loạt các kịch bản Ấn Độ là tốt, vì vậy nó có lẽ nên thực sự được gọi là contains_asian?

Có lẽ tôi nên trân trọng điều này cho các tin tặc I18N nghèo khác bị kẹt với Ruby 1.8.

+0

Tôi nghĩ những người khác có thể thấy nó hữu ích. – Geo

+0

Tôi có một dự án bị mắc kẹt trên 1,8, quá. Giải pháp này đã không làm việc cho tôi, nhưng tôi đã điều chỉnh một giải pháp từ một luồng Stack Overflow khác - xem câu trả lời của tôi ở đây. –

1

Tôi đã viết một viên ngọc nhỏ mà gói lên phương pháp này trong câu trả lời steenslag của trên:

https://github.com/jpatokal/script_detector

Nó cũng có thể mất một đâm vào sự khác biệt giữa Nhật Bản, Hàn Quốc, tiếng Trung giản thể và truyền thống Trung Quốc, mặc dù do sự phức tạp của sự thống nhất Hán nó chỉ hoạt động đáng tin cậy với các mảng văn bản lớn.

0

Ruby 1,8 giải pháp dựa trên this code và sử dụng API từ giải pháp Josh Glover về chủ đề này:

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 
Các vấn đề liên quan