2021-01-15 00:09:20
Строки, символы и Юникод
Периодически паршу (парсю?) всякие тексты, и возникает желание собрать качественный материал на тему строк и символов.
The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!) by Joel Spolsky: обзор на Юникод без привязки к каким-либо языкам программирования.
Storing UTF-8 Encoded Text with Strings from Rust Book: как Юникод представлен в Расте, чем байты отличаются от кодпоинтов или символов и что такое кластеры графем.
Так, мы же тут про Джаву. В 1995 казалось, что 65 536 символов хватит всем, поэтому был выбран UTF-16, в котором char — два байта, а .charAt работает за константное время. Но количество символов в Юникоде уже перевалило за миллион, а это чуть больше, чем 65к, поэтому не все символы вмещаются в два байта. В итоге char содержит обман в своём названии, так как может оказаться половинкой длинного символа («суррогатной пары»), .length() иногда привирает, а за константное время можно получить только немного самообмана.
Настоящий кодпоинт помещается в int. В классе Character у большинства методов есть оверлоады для char и int.
Настоящее итерирование символов можно подсмотреть в ретрофите, например.
У CharSequence есть метод .codePoints(), который возвращает IntStream. Так, количество кодпоинтов можно посчитать за линейное время, вызвав .codePoints().count().
Ну а для работы с кластерами графем есть BreakIterator.getCharacterInstance. Уж он-то не только не станет разрывать кодпоинты, но и не будет отковыривать от букв ударения, а от смайлов — модификаторы и джоинеры.
1.1K viewsedited 21:09