Hello!

> Если нужна посимвольная обработка, определение типа (буква, знак препинания
> и т.п.), преобразование (регистра, убирание акцента,…), то удобнее работать
> с представлением, в котором размер каждого символа одинаков. Иначе всё
> равно каждый символ пришлось бы преобразовывать при извлечении из строки.
> Да и индексация, замена возможны.
>
> Но для этого совершенно не подходят старые функции работы со строками,
> программу нужно писать по-другому.
>
> Если же достаточно ввода/вывода, запросить у пользователя имя, вывести его
> же, или сохранить в файле, чтобы вывести после, то удобнее использовать
> UTF-8. При этом не нужно переписывать полностью старые программы,
> большинству вообще не нужна переделка. Большинство функций для работы с
> 8-битовыми строками будут с таким же успехом работать и с UTF-8 (а вот
> UTF-16 и UTF-32 не подойдут), по крайней мере в старой области значений.
>
> Поэтому UTF-8 используют как стандартное внешнее представление (чтобы с
> данными работали другие программы) и как внутреннее, если не нужна сложная
> работа со строками, учитывающая уникодность.

Спасибо за подробное объяснение. Вопрос в том, что движок СУБД SQLite, с 
которой я работаю, имеет 
два внутренних представления - utf8 и utf16. Во втором случае я могу 
пользоваться системными 
функциями для преобразования и сравнения символов (строк), а вот в случае utf8 
не получается. 
Делать лишние преобразования чревато определенными потерями в 
производительности на всех 
сортировках/сравнениях текстовых данных. Сам движок умеет разделять строку utf8 
на символы, 
остается добавить функции сравнения/преобразования регистров. Данных в utf16 у 
меня сейчас нет, 
поскольку база заполняется при локали системы UTF-8. После ваших подсказок 
появилась мысль, что для 
utf8 можно сделать локале-независимую, а для utf16 - локале-зависимую 
реализации и выбирать формат 
хранения данных в зависимости от потребностей. Может быть, вы можете дать 
оценку такому варианту? Я 
не тестировал скорость обработки utf8/utf16, но по таблицам символов должно 
быть все равно, какое 
представление выбрано, если таблицы составлены в нем же, а системные функции 
быстрее должны 
работать с utf16, но размер данных увеличится...

> > Про UTF-16BE я уже понял, но вот буква Ё пропадает. А если через iconv
> > передавать, все ок.
>
> А откуда ты берёшь Ё в UTF-16BE? Ты уверен, что это именно Ё? Подозреваю,
> что ты ошибся с преобразованием. Ни "Ё", ни L"Ё" не даст тебе Ё в UTF-16BE
> на большинстве систем (к которым ты имеешь доступ).

Уверен, поскольку могу указать явно, в каком формате мне нужны данные - 
sqlite3_value_text16, 
sqlite3_value_text16be, sqlite3_value_text16le, sqlite3_value_text (последняя 
функция вернет 
utf-8). Вызов unac_string работает корректно, а unac_string_utf16 "ломает" 
данные.

void unaccFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
  char *z1 = 0;
  const char *z2;
  int n, l = 0;
  if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;

  z2 = (const char*)sqlite3_value_text16(argv[0]);
  n = sqlite3_value_bytes16(argv[0]);

  /* Verify that the call to _bytes16() does not invalidate the _text16() 
pointer */
  assert( z2==(char*)sqlite3_value_text16(argv[0]) );
  if( z2 ){
        //unac_string("UTF-8", z2, n, &z1, &l);
        if(unac_string("UTF-16", z2, n, &z1, &l) == -1) {
                sqlite3_result_null;
                return;
        }
        //unac_string_utf16(z2, n, &z1, &l);
        sqlite3_result_text16(context, z1, l, SQLITE_TRANSIENT);
  }
}

> > Как сделать "в один ход"
> > сравнение multibyte строк (символов)? В примерах, что я видел,
> > разработчики таскают с собой таблицы для сравнения юникодных символов,
> > зато могут работать с многобайтовыми строками, не занимаясь бесконечными
> > преобразованиями.
>
> Чтобы посимвольно сравнивать многобайтовые строки, необходимо посимвольно
> извлекать из них символы для сравнения (с/без учётом акцентов, регистров и
> т.п.). Т.е. декодировать последовательно каждую из строк. Для каждого
> сравнения. Все строки.
>
> Но если нам не нужен алфавитный порядок, если нужно просто упорядочить
> строки (для деревьев, для бинарного поиска), то можем просто использовать
> strcmp для многобайтовых строк в UTF-8. UTF-8 имеет такое свойство, что
> результат этого сравнения будет совпадать с результатом посимвольного
> сравнения кодов уникодных символов.

Да, так оно и сделано по умолчанию, но мне нужно сортировать по алфавиту 
(игнорируя акценты у "ё" 
и "й"), делать регистронезависимый поиск и приведение регистра. Впрочем, без 
учета системной локали 
это делается "в лоб" с помощью таблиц символов.

P.S. Кстати, напоминаю, что продолжаю писать и собирать дополнительные модули 
для SQLite. Для работы 
с юникодом сейчас есть две реализации - таблицы преобразований и через libicu, 
думаю насчет 
локале-зависимой, но от последней пока только функции upper/lower сделаны :-) 
Недавно добавил 
сибэйзовскую функцию current_user() для облегчения миграции на эскулайт и 
обращение к переменным 
окружения. Если кому надо или есть свои наработки - милости просим.

Best regards, Alexey.


--
To UNSUBSCRIBE, email to debian-russian-requ...@lists.debian.org
with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org

Ответить