Как я могу обнаружить определенные символы Unicode в строке в Ruby? - PullRequest
16 голосов
/ 13 января 2011

Учитывая строку в 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.

Ответы [ 4 ]

42 голосов
/ 13 января 2011

(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 персонажа.
Поддерживаются следующие сценарии: арабский, армянский, балийский, бенгальский, бопомофо, шрифт Брайля, бугинскийBuhid, Canadian_Aboriginal, Carian, Cham, Cherokee, Common, Coptic, Cuneiform, Кипр, Кириллица, Дезерет, Деванагари, Эфиопский, Грузинский, Глаголица, Готский, Греческий, Гуджарати, Гурмукхи, Хан, Хангул, Хануно, Хевериан, Хевери, Каннада, Катакана, Kayah_Li, Харошти, Кхмерский, Лаосский, Латиноамериканский, Лепча, Лимбу, Linear_B, Ликийский, Лидийский, Малайялам, Монгольский, Мьянма, New_Tai_Lue, Нко, Огам, Ол-Чики, Олд-Итал, Ориан-Пьяц, Пьяця, Реджанг, Рунический, Саураштра, Шавский, Сингальский, Сунданский, Силоти-Нагри, Сирийский, Тагальский, Тагбанва, Тай_Ле, Тамильский, Телугу, Таана, Тайский, Тибетский, Тифинагский, Угаритский, Вайский и Йи.

Вау. Источник Ruby Regexp .

9 голосов
/ 13 января 2011

Учитывая мои ограничения на 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

Довольно хакерски, но это работает.На самом деле он также обнаруживает множество индийских сценариев, так что, вероятно, его действительно следует называть содержит_асиан?

Может быть, мне стоит исправить это для других бедных хакеров I18N, придерживающихся Ruby 1.8.

1 голос
/ 04 июня 2012

Я написал небольшую жемчужину, которая объединяет подход в ответе steenslag выше:

https://github.com/jpatokal/script_detector

Он также может помочь в различении японского, корейского и упрощенного китайскогои традиционный китайский, хотя из-за сложностей ханьского объединения он надежно работает только с большими текстовыми блоками.

0 голосов
/ 14 декабря 2013
Решение

Ruby 1.8 на основе этого кода и использования API из решения Джоша Гловера в этой теме:

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
...