mysql

您所在的位置:网站首页 perl获取字符串长度 mysql

mysql

2024-07-07 01:01| 来源: 网络整理| 查看: 265

我编写了一个小型 Perl 函数,它接受一个字符串并检查其长度(不含空格)。基本代码如下:

sub foo { use utf8; my @wordsArray = split(/ /, $_[0])); my $result = length(join('', @wordsArray)); return $result; }

当我向此函数提供包含特殊字符(例如希伯来字母)的字符串时,它似乎工作得很好。 当我使用来自 MySql 列的值(字符集为 utf8mb4)时,问题就开始了:在这种情况下,计算的值高于上一个示例中的值。

我可以猜测为什么会出现这种行为:特殊字符在表中以 4 字节的方式写入,因此每个字母在 utf8 编码中计算为两个字符。

有谁知道如何解决上述问题,以便我从定义为 utf8mb4 的数据库表中获得正确数量的字符?

编辑:

有关上述代码的更多信息:

用作函数参数的 DB 列的类型为 VARCHAR(1000),排序规则为 utf8mb4_unicode_ci。 我通过配置如下的 MySql 连接获取行:

$mySql = DBI->connect( "DBI:mysql:$db_info{'database'}:$db_info{'hostname'};mysql_multi_statements=1;", "$db_info{'user'}", "$db_info{'password'}", {'RaiseError' => 1,'AutoCommit' => 0}); ... $mySql->do("set names utf8mb4");

示例数据值是“שלום עולם”(希伯来语意思是“Hello World”)。

1) 当调用 foo($request->{VALUE}); (其中 VALUE 是来自 DB 的列数据)时,结果为 16(其中每个希伯来字符被计为两个字符) ,并且忽略它们之间的一个空格)。本例中的转储器是:

$VAR1 = "\327\251\327\234\327\225\327\235 \327\242\327\225\327\234\327\235";

2) 当调用 foo("שלום עולם"); 时:

当声明use utf8;时,结果是8(因为该字符串中有8个可见字符)。本例中的转储器(Useqq=1)是:

$VAR1 = "\x{5e9}\x{5dc}\x{5d5}\x{5dd}\x{5e2}\x{5d5}\x{5dc}\x{5dd}";

当不声明`use utf8;'时,结果是16,与从DB发送值的情况类似:

$VAR1 = "\327\251\327\234\327\225\327\235\327\242\327\225\327\234\327\235";

看起来我需要找到一种方法,在开始使用之前将接收到的值转换为 UTF8。

最佳答案

MySQL 所称的 utf8 是 UTF-8 的有限子集,每个字符仅允许三个字节,并且覆盖最大 0xFFFF 的代码点。即使 utf8mb4 也没有涵盖完整的 UTF-8 范围,该范围支持最长 6 个字节的编码字符

结果是,来自 utf8 或 utf8mb4 列的任何数据都只是 Perl 中的 UTF-8 字符串,两个数据库之间应该没有区别编码

我猜测您尚未为 DBI 句柄启用 UTF-8,因此所有内容都被视为字节序列。当您进行 connect 调用时,您应该启用 mysql_enable_utf8,这应该类似于

my $dbh = DBI->connect($dsn, $user, $password, { mysql_enable_utf8 => 1 });

通过附加数据,我可以看到您从数据库检索的字符串确实是 UTF-8 编码的

但是,如果我对其进行解码,那么首先我会从您的 foo 子例程和我自己的子例程中获得非空格字符数,而不是 9;而且您应该从数据库中获取字符,而不是字节

我怀疑您可能首先将编码字符串写入数据库。下面是一个简短的程序,它创建一个 MySQL 表,向其中写入两条记录(一条字符串和一条编码字符串)并检索所写入的内容。您将看到唯一有所不同的是 mysql_enable_utf8 的设置。无论原始字符串是否经过编码,以及是否使用 SET NAMES utf8mb4

,行为都是相同的

进一步的实验表明mysql_enable_utf8或SET NAMES utf8mb4将使DBI写入数据正确,但后者对读取没有影响

我建议您的解决方案应该是在读取或写入时仅使用mysql_enable_utf8

您还应该仅在所有程序的顶部使用 utf8。错过这一点意味着您不能在代码中使用任何非 ASCII 字符

use utf8; use strict; use warnings; use DBI; use open qw/ :std :encoding(utf-8) /; STDOUT->autoflush; my $VAR1 = "\327\251\327\234\327\225\327\235 \327\242\327\225\327\234\327\235"; my $dbh = DBI->connect( qw/ DBI:mysql:database=temp admin admin /, { RaiseError => 1, PrintError => 0, mysql_enable_utf8 => 1, } ) or die DBI::errstr; $dbh->do('SET NAMES utf8mb4'); $dbh->do('DROP TABLE IF EXISTS temp'); $dbh->do('CREATE TABLE temp (value VARCHAR(64) CHARACTER SET utf8mb4)'); my $insert = $dbh->prepare('INSERT INTO temp (value) VALUES (?)'); $insert->execute('שלום עולם'); $insert->execute($VAR1); my $values = $dbh->selectcol_arrayref('SELECT value FROM temp'); printf "string: %s foo: %d\n", $_, foo($_) for @$values; sub foo2 { $_[0] =~ tr/ //c; } sub foo { length join '', split / /, $_[0]; }

使用 mysql_enable_utf8 => 1 输出

string: שלום עולם foo: 8 string: שלום עולם foo: 8

输出为mysql_enable_utf8 => 0

string: ש××× ×¢××× foo: 16 string: ש××× ×¢××× foo: 16

关于mysql - 使用perl从MySql获取utf8mb4字符串的长度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30290384/



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3