Подтвердить что ты не робот

Как сделать MySQL осведомленным о многобайтовых символах в LIKE и REGEXP?

У меня есть таблица MySQL с двумя столбцами, как с utf8_unicode_ci. Он содержит следующие строки. За исключением ASCII, второе поле также содержит кодовые точки Unicode, такие как U + 02C8 (MODIFIED LETTER VERTICAL LINE) и U + 02D0 (MODIFIED LETTER TRIANGULAR COLON).

 word   | ipa
--------+----------
 Hallo  | haˈloː
 IPA    | ˌiːpeːˈʔaː

Мне нужно искать второе поле с LIKE и REGEXP, но MySQL (5.0.77), кажется, интерпретирует эти поля как байты, а не как символы.

SELECT * FROM pronunciation WHERE ipa LIKE '%ha?lo%';  -- 0 rows
SELECT * FROM pronunciation WHERE ipa LIKE '%ha??lo%'; -- 1 row

SELECT * FROM pronunciation WHERE ipa REGEXP 'ha.lo';  -- 0 rows
SELECT * FROM pronunciation WHERE ipa REGEXP 'ha..lo'; -- 1 row

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

Как я могу решить эту проблему? Если это невозможно: существует ли правдоподобная работа, которая не требует обработки всей базы данных с помощью PHP каждый раз? Есть 40 000 строк, и я не настроен на использование MySQL (или UTF8, если на то пошло). У меня есть только доступ к PHP и MySQL на хосте.

Изменить: Существует открытый 4-летний отчет об ошибке MySQL, Ошибка # 30241 Проблемы с регулярным выражением, который отмечает, что двигатель regexp работает побайтно. Таким образом, я ищу работу.

4b9b3361

Ответ 1

EDITED, чтобы включить исправление в действительный критизм

Используйте функцию HEX(), чтобы сделать ваши байты шестнадцатеричными, а затем используйте RLIKE, например:

select * from mytable
where hex(ipa) rlike concat('(..)*', hex('needle'), '(..)*'); -- looking for 'needle' in haystack, but maintaining hex-pair alignment.

Нечетные символы unicode последовательно отображают их шестнадцатеричные значения, поэтому вы просматриваете стандартные символы 0-9A-F.

Это работает и для "нормальных" столбцов, вам просто не нужно.

p.s. @Kieren (действительная) точка, адресованная с помощью RLIKE для принудительного использования пар char

Ответ 2

Я не настроен на использование MySQL

Postgres, похоже, справляется с этим довольно хорошо:

test=# select 'ˌˈʔ' like '___';
 ?column? 
----------
 t
(1 row)

test=# select 'ˌˈʔ' ~ '^.{3}$';
 ?column? 
----------
 t
(1 row)

Если вы спуститесь по этой дороге, обратите внимание, что оператор Postgres ilike совпадает с оператором MySQL like. (В Postgres like зависит от регистра.)


Для решения, специфичного для MySQL, вы не можете работать, привязав определенную функцию пользовательскую функцию (возможно, привяжите библиотека ICU?) в MySQL.

Ответ 3

У вас проблемы с UTF8? Устраните их.

Сколько специальных символов вы используете? Вы используете только локализационные буквы, верно? Итак, мой совет: Напишите функцию, которая преобразует spec-символы в обычные символы, например. "æ" → "A" и т.д. и добавьте столбец в таблицу, в которой хранится это преобразованное значение (вам нужно сначала преобразовать все значения и каждую вставку/обновление). При поиске вам просто нужно преобразовать строку поиска с той же функцией и использовать ее в этом поле с регулярным выражением.

Если слишком много специальных символов, вы должны преобразовать его в multi- char. 1. Избегайте нахождения "aa" в последовательности "ba ab", используя некоторый префикс, например "@ba @ab". 2. Избегайте нахождения "@a" в "@ab" использовать токены фиксированной длины, скажем, 2.