提问人:Alex Regan 提问时间:10/22/2022 更新时间:10/23/2022 访问量:199
执行失败:字符串值不正确:“\xE4rvine...”使用 mariadb 和 perl DBD
execute failed: Incorrect string value: '\xE4rvine...' with mariadb and perl DBD
问:
三年多前,我发布了一个类似的问题,与我认为字符集不正确而无法将数据插入表有关,而今天我使用不同的数据使用相同的脚本也遇到了同样的问题。
问题出在 Ilpo J rvinen 中的德语字符(带有变音符号的“a”?
执行失败:字符串值不正确:“\xD6sterl...”使用 mariadb 和 perl DBD
DBD::mysql::st execute failed: Incorrect string value: '\xE4rvine...' for column `lsv6`.`xyz_content`.`fulltext` at row 1 at myscript.pl line 467.
我正在尝试处理具有不同字符集的电子邮件,但显然我的脚本没有正确编码。从电子邮件:
Content-type: text/plain; charset="iso-8859-1"
Content-transfer-encoding: quoted-printable
完整的脚本太长,无法在此处发布,但我相信这些是涉及数据库的相关部分。
sub db_connect($) {
...
return DBI->connect("DBI:mysql:database=$DB{'db'};host=$DB{'host'}", $DB{'user'}, $DB{'pass'}, { PrintError => 1, RaiseError => 1, mysql_enable_utf8mb4 => 1 } )
...
}
$fullText = $dbh->quote($fullText);
my $sql = <<EOF;
INSERT INTO xuxgc_content (title, alias, introtext, `fulltext`, state, catid, created, created_by, created_by_alias, modified, modified_by, checked_out, checked_out_time, publish_up, publish_down, images, urls, attribs, version, ordering, metakey, metadesc, metadata, access, hits, language)
VALUES ($title, "$title_alias", $introText, $fullText, $state, $catid, $created, $created_by, $created_by_alias, $modified, $modified_by, $checked_out, $checked_out_time, $publish_up, $publish_down, $images, $urls, $attribs, $version, $ordering, $metakey, $metadesc, $metadata, $access, $hits, $language);
EOF
my $sth = $dbh->prepare($sql);
$sth->execute();
db_disconnect($dbh);
如果我去掉非 ASCII 字符,它可以正常工作:
$fullText =~ s/\xE4//g;
$fullText =~ s/\xFC//g;
$fullText =~ s/\xE5//g;
我应该使用 iso-8859-1 编码而不是 utf8mb4 吗?
答:
$fullText
是使用 ISO-8859-1 编码的文本字符串。在使用它之前,需要将其解码为文本字符串。
DBD::mysql 期望对字符串进行适当的编码以进行连接。在您的情况下,这是 UTF-8。[1] 因此,您需要将查询编码为字符串字节,然后再将其传递给 DBD::mysql。
# Convert bytes to text
my $fullText = decode( "iso-8859-1", $fullText_latin1 );
# Convert text to SQL string literal
my $fullText_lit = $dbh->quote( $fullText );
my $sql = "... $fullText_lit ...";
# Convert text to bytes
my $sql_utf8 = encode( "UTF-8", $sql );
my $sth = $dbh->prepare( $sql_utf8 );
请注意,DBD::mysql 存在 Unicode 错误。
Perl 有两种字符串的内部存储格式:“降级”和“升级”。字符串使用哪种内部存储格式并不重要。但是 DBD::mysql(以及我所知道的所有其他 DBD)访问内部字符串缓冲区,而不检查使用了两种存储格式中的哪一种。据说执行此操作的代码会受到Unicode错误的影响。
所以我之前说的不太对。DBD::mysql 期望字符串的内部缓冲区为连接进行适当的编码。 始终以降级格式生成字符串,并且此类字符串的内部缓冲区始终完全包含该字符串。encode
这意味着只要您使用正确的编码对传递给 DBD::mysql 的字符串进行编码,就不会有问题。encode
- 作为连接选项传递的效果之一是将编码连接设置为 UTF-8,就像使用 一样。
mysql_enable_utf8mb4 => 1
SET NAMES utf8mb4
评论
a
b
encode
评论
$fullText = decode( "iso-8859-1", $fullText );