Внутренние классы String - кэширование смещения символа к байтовому отношению при использовании UTF-8 - PullRequest
1 голос
/ 21 декабря 2009

При написании пользовательского строкового класса, который хранит UTF-8 внутренне (для экономии памяти), а не UTF-16 с нуля, возможно ли в некоторой степени кэшировать связь между байтами смещение и смещение символа для увеличения производительности, когда приложения используют класс с произвольным доступом?

Perl выполняет этот тип кэширования отношения смещения символа к смещению байта? Как строки Python работают внутри?

А как насчет Objective-C и Java? Они используют UTF-8 для внутреннего использования?

EDIT

Найдена эта ссылка на Perl 5, использующую UTF-8 внутри:

"$ flag = utf8 :: is_utf8 (STRING)

(Начиная с Perl 5.8.1) Проверьте, находится ли STRING внутри UTF-8. Функционально так же, как Encode :: is_utf8 (). "

На странице

http://perldoc.perl.org/utf8.html

EDIT

В приложениях, которые я имею в виду, строки содержат 1-2К строф XML в потоке XMPP. Около 1% сообщений будут иметь до 50% (по количеству символов) значений Unicode> 127 (это XML). На серверах сообщения проверяются по правилам и направляются условно на небольшое (по объему символов) подмножество полей. Серверы - это ящики Wintel, работающие на ферме. В клиентах данные поступают и поступают в инструментарий пользовательского интерфейса.

EDIT

Но приложение неизбежно будет развиваться и хотеть сделать произвольный доступ тоже. Можно ли свести к минимуму снижение производительности, когда это произойдет: меня также интересовало, существует ли более общий дизайн класса, который, например, управляет b-деревьями отношения смещения символов <-> байтов для больших строк UTF8 (или каким-либо другим алгоритмом, признанным эффективным в общий случай.)

Ответы [ 3 ]

2 голосов
/ 22 декабря 2009

Perl различает строки Unicode и не-Unicode. Строки Unicode реализованы с использованием UTF-8 внутри. Non-Unicode не обязательно означает 7-битный ASCII, хотя это может быть любой символ, который может быть представлен в текущей локали в виде одного байта.

1 голос
/ 21 декабря 2009

Внутренние строки Java имеют UTF-16 внутри:

String представляет строку в формате UTF-16, в которой дополнительные символы представлены суррогатными парами (см. Раздел Представления символов Unicode в классе Character для получения дополнительной информации). Значения индекса относятся к единицам кодов символов, поэтому дополнительный символ использует две позиции в строке.

java.lang.String

1 голос
/ 21 декабря 2009

Я думаю, что ответ таков: в общем, не стоит пытаться это делать. В вашем конкретном случае, может быть.

Если большинство ваших символов - простые ASCII, и у вас редко встречаются последовательности UTF, то, возможно, стоит построить некую разреженную структуру данных со смещениями.

В общем случае каждый отдельный символ может быть не-ASCII, и у вас может быть много смещений для хранения. На самом деле, наиболее общий случай - создать строку байтов, которая будет в точности соответствовать длине строки символов Unicode, и каждое значение байта будет смещением следующего символа. Но это означает один целый байт на символ и, следовательно, чистую экономию всего одного байта на символ Юникода; вероятно, не стоит усилий. И это означает, что индексирование в вашей строке теперь является операцией O (n), когда вы пробегаете эти смещения и суммируете их, чтобы найти фактический индекс.

Если вы хотите попробовать разреженную структуру данных, я предлагаю массив пар значений, первое из которых является индексом в строке Unicode символа, а второе - индексом в последовательности байтов, где это персонаж действительно появляется. Затем после каждой escape-последовательности UTF8 вы должны добавить два значения, чтобы найти следующий символ в строке. Наконец, когда задан индекс для символа Unicode, ваш код может выполнить двоичный поиск в этом массиве, чтобы найти самый высокий индекс в разреженном массиве, который меньше запрашиваемого индекса, а затем использовать его для поиска фактического байта, который представляет начало нужного символа.

Если вам нужно сэкономить память, вы можете рассмотреть возможность использования библиотеки сжатия данных. Хлебать строки Юникода как полный Юникод, затем сжимать их; затем для индексации в строку, сначала вы распаковываете эту строку. Это действительно сэкономит память, и будет легко и быстро получить правильный код, чтобы он работал; но это может добавить слишком много ресурсов процессора, чтобы быть разумным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...