Можно побайтно просматривать строку, как обычно, с помощью итератора each_byte
. А можно просматривать посимвольно с помощью итератора each_char
. Второй способ имеет дело с односимвольными строками, первый (в текущей версии Ruby) — с однобайтными целыми. Разумеется, мы в очередной раз приравниваем кодовую позицию к символу. Несмотря на название, метод 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
есть параметры, помогающие манипулировать Unicode-строками. Указав в форматной строке параметр U*
, мы можем преобразовать строку в кодировке UTF-8 в массив кодовых позиций ( 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#{eacute}" # "café"
Регулярным выражениям тоже известно о многобайтовых символах, особенно если вы пользуетесь библиотекой Oniguruma (мы рассматривали ее в главе 3). Например, образец /./
сопоставляется с одним многобайтовым символом.
Модификатор u
извещает регулярное выражение о том, что мы работаем с кодировкой UTF-8. Если $KCODE
равно "u"
, то модификатор можно не задавать, однако это и не повредит. (К тому же такая избыточность может быть полезна, если код является частью большой программы, а какое значение переменной $KCODE
в ней установлено, вам неизвестно.)
Даже без Oniguruma регулярные выражения распознают, относится ли данный многобайтовый символ к категории тех, что могут входить в состав слова:
$KCODE = "u"
sword =~ /\w/ #0
sword =~ /\W/ # nil
При наличии Oniguruma последовательности, начинающиеся с символа обратной косой черты ( \w
, \s
и т.п.) распознают и более широкие диапазоны кодовых точек: слова, пропуски и т.д.
Регулярные выражения позволяют безопасно выполнять простые манипуляции со строками. Мы и так можем без труда усекать строки. Следующий код возвращает не более 20 символов из строки ascii_string
:
ascii_string[0,20]
Однако, поскольку кодовая позиция Unicode может занимать более одного байта такую технику нельзя безопасно применять к строке в кодировке UTF-8. Есть риск, что в конце строки окажется недопустимая последовательность байтов. Кроме того, это не слишком полезно, так как мы не можем заранее сказать, сколько в результате получится кодовых позиций. На помощь приходят регулярные выражения:
Читать дальше
Конец ознакомительного отрывка
Купить книгу