Прежде всего, пожалуйста, следуйте документации - модуль utf8
должен only использоваться в 'use utf8;' Форма, чтобы указать, что ваш исходный код UTF-8 вместо Latin-1. Не используйте никакие функции utf8.
Perl различает байты и строки UTF-8. В байтовом режиме Perl не знает и не заботится о том, какую кодировку вы используете, и будет использовать Latin-1, если вы его напечатаете. Взять, к примеру, знак евро (€). В UTF-8 это 3 байта, 0xE2, 0x82, 0xAC. Если вы напечатаете длину этих байтов, Perl вернет 3. Опять же, это не заботится о кодировке. Это могут быть любые байты или любая кодировка, легальная или нелегальная.
Если вы используете модуль Encode
и вызовете Encode::decode("UTF-8', $bytes)
, вы получите новую строку с установленным так называемым флагом UTF8. Perl теперь знает, что ваша строка в UTF-8, и вернет длину 1.
Проблема в том, что utf8::valid
относится только ко второму типу строки. Ваши строки, вероятно, в первой форме, в байтовом режиме, и utf8::valid
просто возвращает true для чего-либо в байтовой форме. Это задокументировано в perldoc.
Решение состоит в том, чтобы заставить Perl декодировать ваши байтовые строки как UTF-8 и обнаруживать любые ошибки. Это можно сделать с помощью FB_CROAK, как объясняет Брайан Д. Фой:
my $ustring =
eval { decode( 'UTF-8', $byte_string, FB_CROAK ) }
or die "Could not decode string: $@";
Затем вы можете перехватить эту ошибку и пропустить эти недопустимые строки.
Или, если вы знаете, что ваш код в основном UTF-8 с несколькими недопустимыми последовательностями здесь и там, вы можете использовать:
my $ustring = decode( 'UTF-8', $byte_string );
, который использует режим по умолчанию FB_DEFAULT
, заменяя недопустимые символы на U + FFFD, символ замены Юникод (ромб с вопросительным знаком в нем).
В большинстве случаев вы можете передать строку непосредственно в драйвер базы данных. Некоторые драйверы могут потребовать, чтобы вы сначала перекодировали строку обратно в байтовую форму:
my $byte_string = encode('UTF-8', $ustring);
В сети также есть регулярные выражения, которые можно использовать для проверки правильности последовательностей UTF-8 перед вызовом decode
(проверьте другие ответы переполнения стека). Если вы используете эти регулярные выражения, вам не нужно кодировать или декодировать.
Наконец, пожалуйста, используйте UTF-8
вместо utf8
в своих вызовах на decode
. Последний является более слабым и позволяет некоторым недопустимым последовательностям UTF-8 (таким как последовательности вне диапазона Unicode) быть позволенным через.