[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Возможна ли поддержка тиклем юникода?



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.


Reply to: