Следуя за длинным рантом рассказываю о том, как я расправляюсь с юникодом в Ruby “своим путем”. Этот подход успешно применяется, в том числе в RuTils и на всех rails-работах, которые я выполняю.

Technorati Tags: , ,

Первое - String в Ruby у всех один, но работает он с байтами. То есть “что-то”.size вернет то же самое что и strlen() в PHP без mbstring. Это надо чинить.

Шаг 0 - (чтобы получить пристойный юникод на STDOUT и получать его из STDIN вместо порядка байтов): $KCODE = ‘u’ require ‘jcode’

Со вторым пунктом некоторые несогласны, но я считаю что он таки нужен (пока) - дает нам string.jsize (который возвращает длину строки в знакоместах(!) а не в байтах). Эти строки надо добавить в Самое Начало Самого Главного И Первого Файла.

Далее. К регулярным выражениям надо добавлять ключ /u (это явно не новость). Новость то, что если $KCODE равен “u” (или, как это указано в полной транскрипции Ruby - ‘UTF8’) то все регулярные выражения по идее должны получить этот ключ автоматически - но я все равно его добавляю для ясности кода. $KCODE помимо прочего даст строкам нормальную Unicode-general сортировку.

Далее - остаются “ВРАГ”.lower и “ну и дела”.upper Для этого нужно применять особое лекарство.

julik@exile#  sudo gem install unicode

Если у вас Windows и нету желания ничего компилировать - скачайте то же самое в бинарном виде отсюда - спасибо Wilson Bilkovich что собрал gem.

Оное расширение делает в числе прочего нормализацию и конверсию регистра для Unicode-строк, вызываемую как

Unicode::upcase("враг")

Что позволяет нам легким движением руки одарить этим функционалом все строки в принципе во всех частях и закоулках нашей программы:

begin
  require 'unicode'
  String.class_eval  'def downcase
     Unicode::downcase(self)
   end
   def downcase!
     self.replace downcase
   end
   
   def upcase
     Unicode::upcase(self)
   end
   def upcase!
     self.replace upcase
   end
   def capitalize
     Unicode::capitalize(self)
   end

   def capitalize!
     self.replace capitalize
   end'
rescue LoadError
   # gem на машине не установлен - об этом полезно ругнуться в логи
end

После этого осталось только напомнить вашей базе SET NAMES / SET ENCODING и работать дальше. На сладкое - поставить gettext - gem install gettext и получить gettext/locale в подарок (например для русских дат).

require 'gettext/locale'
Locale.set(Locale::ALL, "ru_RU.UTF-8")
Time.now # => ср ноя 30 02:00:48 CET 2005

или RuTils как временный хак (пока администратор не поставит вам gettext). Как по мне - чего еще надо? Остальные нужды обслужит iconv, встроенный в стандартную библиотеку Ruby.

Да, увы, вышеупомянутое чинит не все.

То есть:

"это текст"[0..2] # работать не будет - режет символы между байтов

но на каждую, как известно…

"это текст".split(//u)[0..2].join # работает