Как быстрее измерить длину строки в Go?
Интересная штука, с которой сталкиваются начинающие разработчики в Гоу — как измерить длину строки в этом языке. То есть речь не идёт даже о быстроте, как, чёрт возьми, вообще это сделать?
Встроенная функция len возвращает длину в байтах, именно поэтому англоязычные разработчики часто и не знают, что проблема есть — строки латиницы, что в байтах, что в символах (в Гоу они называются «руны») занимают одинаково.
Я знаю два способа измерить длину строки:
package main
import ("io/ioutil"; "unicode/utf8")
func main() {
bytes, _ := ioutil.ReadFile("test.txt")
// считаем сколько рун встречается в строке
print(utf8.RuneCountInString(string(bytes)))
print("\n")
// считаем длину массива рун
print(len([]rune(string(bytes))))
}
По работе понадобилось измерить длину строки быстро — у меня здоровый цикл, где она постоянно измеряется, оказалось, что в тысяче итераций на тексте книги «На всех пара́х» Терри Пратчетта разница в две секунды — выигрывает преобразование в массив «рун».
Нужен быстрый способ — используйте len([]rune(…)).
Боюсь показаться занудой. Но руны — это кодовые точки, а не символы (хотя и достаточно близко для русского языка). Но иногда это может оказаться неожиданным (особенно — в контексте безопасности или криптографии).
Комментарий для dmitry-vk.livejournal.com:
Не понял комментария, раскройте мысль, пожалуйста!
Некоторые буквы (например, такие, как «ё») в юникоде имеют несколько представлений: в виде precomposed character (тогда буква занимает одну руну) и в виде пары символ + combining character (тогда буква занимает две руны: одна руна — базовый символ, и еще одна руна — комбинирующий символ).
Приведу пример кода:
http://pastebin.com/hAvYX5ya
Советую почитать вот это (про JavaScript, но главное не в этом): http://mathiasbynens.be/notes/javascript-unicode
Комментарий для dmitry_vk.livejournal.com:
Дмитрий, вы перепутали символы и буквы. Все буквы — символы, не все символы — буквы.
Комментарий для blog.fxposter.org:
Спасибо, но тему Юникода я знаю очень хорошо.