Программирование на языке Ruby - Страница 54
Ознакомительная версия. Доступно 54 страниц из 266.Возможно, вы думаете, что неакцентированные символы в некотором смысле эквивалентны своим акцентированным вариантам. Это почти всегда не так. Здесь мы имеем дело с разными символами. Убедимся в этом на примере метода
count
$KCODE = "u"
sword.count("e") # 1 (не 3)
Но для составных (не монолитных) символов верно прямо противоположное. В этом случае латинская буква распознается.
Метод
count
jcount
$KCODE = "u"
sword.count("eé") # 5 (не 3)
sword.jcount("eé") # 3
Существует вспомогательный метод
mbchar?
$KCODE = "u"
sword.mbchar? # 0 (смещение первого многобайтового символа)
"foo".mbchar? # nil
В библиотеке
jcode
chop
delete
squeeze
succ
tr
tr_s
jcode
Можно побайтно просматривать строку, как обычно, с помощью итератора
each_byte
each_char
each_char
$KCODE = "u"
sword.each_byte {|x| puts x } # Шесть строк с целыми числами.
sword.each_char {|x| puts x } # Четыре строки со строками.
Если вы запутались, не переживайте. Все мы через это проходили. Я попытался свести все вышесказанное в таблицу 4.1.
Таблица 4.1. Составные и монолитные формы
Монолитная форма "é" | ||||
---|---|---|---|---|
Название символа | Глиф | Кодовая позиция | Байты UTF-8 | Примечания |
Строчная латинская e с акутом | é | U+00E9 | 0xC3 0хА9 | Один символ, одна кодовая позиция, один байт |
Составная форма "é" | ||||
Название символа | Глиф | Кодовая позиция | Байты UTF-8 | Примечания |
Строчная латинская е | е | U+0065 | 0x65 | Один символ, две кодовых позиции (два «программистских символа»), три байта UTF-8 |
Модифицирующий акут | ́ | U+0301 | 0xCC 0x81 |
Что еще надо учитывать при работе с интернациональными строками? Квадратные скобки по-прежнему относятся к байтам, а не к символам. Но при желании это можно изменить. Ниже приведена одна из возможных реализаций (не особенно эффективная, зато понятная):
class String
def [](index)
self.scan(/./)[index]
end
def []=(index,value)
arr = self.scan(/./)
arr[index] = value
self.replace(arr.join)
value
end
end
Конечно, здесь не реализована значительная часть функциональности настоящего метода
[]
У метода
unpack
U*
U
codepoints = sword.unpack('U*') # [233, 112, 233, 101]
Вот несколько более полезный пример, в котором все кодовые позиции в строке, отличные от ASCII (то есть начиная с U+0080), преобразуются к виду U+XXXX, который мы обсуждали выше:
def reveal_non_ascii(str)
str.unpack('U*').map do |cp|
if cp < 0x80
cp.chr
else
'(U+%04X)' % cp
end
end.join
end
У метода
String#unpack
Array#pack
[233, 112, 233, 101].pack('U*') # "épée"
Мы можем воспользоваться им, чтобы вставить Unicode-символы, которые трудно ввести с клавиатуры:
eacute = [0хЕ9].pack('U')
cafe = "caf#" # "café"
Регулярным выражениям тоже известно о многобайтовых символах, особенно если вы пользуетесь библиотекой Oniguruma (мы рассматривали ее в главе 3). Например, образец
/./