Unicode и Ruby
Следуя за длинным рантом рассказываю о том, как я расправляюсь с юникодом в Ruby “своим путем”. Этот подход успешно применяется, в том числе в RuTils и на всех rails-работах, которые я выполняю.
Technorati Tags: rails, ruby, unicode
Первое - 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 # работает