- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我编写了一个小型 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/
如何使用 SPListCollection.Add(String, String, String, String, Int32, String, SPListTemplate.QuickLaunchO
我刚刚开始使用 C++ 并且对 C# 有一些经验,所以我有一些一般的编程经验。然而,似乎我马上就被击落了。我试过在谷歌上寻找,以免浪费任何人的时间,但没有结果。 int main(int argc,
这个问题已经有答案了: In Java 8 how do I transform a Map to another Map using a lambda? (8 个回答) Convert a Map>
我正在使用 node + typescript 和集成的 swagger 进行 API 调用。我 Swagger 提出以下要求 http://localhost:3033/employees/sear
我是 C++ 容器模板的新手。我收集了一些记录。每条记录都有一个唯一的名称,以及一个字段/值对列表。将按名称访问记录。字段/值对的顺序很重要。因此我设计如下: typedef string
我需要这两种方法,但j2me没有,我找到了一个replaceall();但这是 replaceall(string,string,string); 第二个方法是SringBuffer但在j2me中它没
If string is an alias of String in the .net framework为什么会发生这种情况,我应该如何解释它: type JustAString = string
我有两个列表(或字符串):一个大,另一个小。 我想检查较大的(A)是否包含小的(B)。 我的期望如下: 案例 1. B 是 A 的子集 A = [1,2,3] B = [1,2] contains(A
我有一个似乎无法解决的小问题。 这里...我有一个像这样创建的输入... var input = $(''); 如果我这样做......一切都很好 $(this).append(input); 如果我
我有以下代码片段 string[] lines = objects.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.No
这可能真的很简单,但我已经坚持了一段时间了。 我正在尝试输出一个字符串,然后输出一个带有两位小数的 double ,后跟另一个字符串,这是我的代码。 System.out.printf("成本:%.2
以下是 Cloud Firestore 列表查询中的示例之一 citiesRef.where("state", ">=", "CA").where("state", "= 字符串,我们在Stack O
我正在尝试检查一个字符串是否包含在另一个字符串中。后面的代码非常简单。我怎样才能在 jquery 中做到这一点? function deleteRow(locName, locID) { if
这个问题在这里已经有了答案: How to implement big int in C++ (14 个答案) 关闭 9 年前。 我有 2 个字符串,都只包含数字。这些数字大于 uint64_t 的
我有一个带有自定义转换器的 Dozer 映射: com.xyz.Customer com.xyz.CustomerDAO customerName
这个问题在这里已经有了答案: How do I compare strings in Java? (23 个回答) 关闭 6 年前。 我想了解字符串池的工作原理以及一个字符串等于另一个字符串的规则是
我已阅读 this问题和其他一些问题。但它们与我的问题有些无关 对于 UILabel 如果你不指定 ? 或 ! 你会得到这样的错误: @IBOutlet property has non-option
这两种方法中哪一种在理论上更快,为什么? (指向字符串的指针必须是常量。) destination[count] 和 *destination++ 之间的确切区别是什么? destination[co
This question already has answers here: Closed 11 years ago. Possible Duplicates: Is String.Format a
我有一个Stream一个文件的,现在我想将相同的单词组合成 Map这很重要,这个词在 Stream 中出现的频率. 我知道我必须使用 collect(Collectors.groupingBy(..)
我是一名优秀的程序员,十分优秀!