【问题标题】:Perl issue when encoding mysql data from UTF-8 to UCS-2 for SMPP将 mysql 数据从 UTF-8 编码为 SMPP 的 UCS-2 时出现 Perl 问题
【发布时间】:2022-01-14 15:56:02
【问题描述】:

我正在尝试从 mysql 获取 UTF-8 重音字符“锓ê”,并在通过 SMPP 发送时将它们转换为 UCS-2。数据存储为 utf8_general_ci,我在打开数据库连接时执行以下操作:

$dbh->{'mysql_enable_utf8'}=1;
$dbh->do("set NAMES 'utf8'");

如果我通过使用 data_encoding=8 用“锓ê”对字符串值进行硬编码来测试发送部分,它会完美地通过。但是,如果我注释掉第一行并只使用来自数据库的内容,它就会失败。此外,如果我尝试使用 DB 发送字符并设置 data_encoding=3,它也可以正常工作,但是不会出现“ê”,这也是预期的。这是我使用的:

$fred = 'éêcole'; <-- If I comment out this line, the SMPP call fails
$fred = decode('utf-8', $fred);
$fred = encode('UCS-2', $fred);

$resp_pdu = $short_smpp->submit_sm(
        source_addr_ton => 0x00,
        source_addr_npi => 0x01,
        source_addr => $didnb,
        dest_addr_ton => 0x01,
        dest_addr_npi => 0x01,
        destination_addr => $number,
        data_coding => 0x08,
        short_message => $fred
) or do {
        Log("ERROR: submit_sm indicated error: " . $resp_pdu->explain_status());
        $success = 0;
};

data_coding 字段的不同值如下: Meaning of "data_coding" field in SMPP

00000000 (0) - usually GSM7
00000011 (3) for standard ISO-8859-1
00001000 (8) for the universal character set -- de facto UTF-16

SMPP 提供程序的文档还提到应通过 UCS-2 处理特殊字符: https://community.sinch.com/t5/SMS-365-enterprise-service/Handling-Special-Characters/ta-p/1137

我应该如何准备来自数据库的数据以使这个 SMPP 调用正常工作?

我正在使用 Perl v5.10.1

谢谢!

【问题讨论】:

  • decode('utf-8', $fred) 在我看来很可疑。 $dbh-&gt;{'mysql_enable_utf8'}=1; 的目的不是解码返回的值吗?如果是这样,解决方法是删除$fred = decode('utf-8', $fred);。如果是这样,您的工作程序可以正常工作,因为它是使用 UTF-8 编码的,但您隐含地告诉 Perl 它是使用 ASCII 编码的,而不是使用 use utf8;
  • 请提供sprintf "%vX", $s 的工作值和失败值(从解码/编码之前开始)。如果我在前面的评论中是对的,那么当它失败时你会看到代码点(E9 代表 é),而当它成功时你会看到一个使用 UTF-9 编码的字符串(C3 A9 代表 é IIRC)。
  • 所以当我使用存储的值并在编码/解码之前打印 sprintf 时,我得到的是:E9.EA.63.6F.6C.65,所以你是对的。然后,如果我删除解码 utf-8 部分并只留下编码 ucs-2,我现在得到“é cole”,缺少 ê。然后,如果我添加使用 utf8;在顶部,我得到了相同的结果。
  • 所以如果我添加使用 utf8;编码 ucs-2 之前的输出为 E9.EA.63.6F.6C.65,一旦编码完成,输出变为 0.E9.0.EA.0.63.0.6F.0.6C.0.65
  • 如果我将 use utf-8 放在顶部,并解码 utf8,解码后的输出是 FFFD.FFFD.63.6F.6C.65 并且一旦编码回 ucs-2输出为 FF.FD.FF.FD.0.63.0.6F.0.6C.0.65

标签: mysql perl encoding smpp ucs2


【解决方案1】:

$dbh-&gt;{'mysql_enable_utf8'} = 1; 用于解码从数据库返回的值,导致查询返回解码后的文本(Unicode 代码点字符串)。解码这样的字符串是没有意义的。直接去encode

my $s_ucp = "\xE9\xEA\x63\x6F\x6C\x65";  # éêcole
# -or-
use utf8; # Script is encoded using UTF-8.
my $s_ucp = "éêcole";

printf "%vX\n", $s_ucp;                  # E9.EA.63.6F.6C.65

my $s_ucs2be = encode('UCS-2', $s_ucp);

printf "%vX\n", $s_ucs2be;               # 0.E9.0.EA.0.63.0.6F.0.6C.0.65

【讨论】:

  • 好的,我显然不太明白它们是如何相互作用的,感谢您的解释。所以如果我注释掉 $dbh->{'mysql_enable_utf8'}=1;和 $dbh->do("set NAMES 'utf8'");现在可以了!如果可以的话,我会给你送 12 杯啤酒 :) 我只花了两天时间。非常感谢您抽出时间来做这件事。
  • 所以我真的认为 $dbh->{'mysql_enable_utf8'} = 1 会以某种方式确保在 perl 变量中将 utf-8 数据分配为 utf-8,就像明确告诉到 perl 哪个编码是用编码的数据
  • Re "会以某种方式确保在 perl 变量中将 utf-8 数据分配为 utf-8",set NAMES 'utf8' 设置了它的编码方式金属丝。 $dbh-&gt;{'mysql_enable_utf8'}=1; 解码 来自 UTF-8。 mysql_enable_utf8 =&gt; 1 传递给 connect 两者兼而有之。
【解决方案2】:

SET NAMES 表示您在客户端中拥有/想要的编码。也就是说,无论表中的编码如何,MySQL 都会将其转换为 SET NAMESSELECT 期间所说的任何内容。

因此,将来自 SELECT 的内容直接提供给 SMPP。 (大多数其他客户端无法读取它。)

SET NAMES ucs2

(排序规则与编码无关。)

您可以要求SELECT 转换类似

CONVERT(col_name, CHAR UNICODE)

https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html

【讨论】:

    猜你喜欢
    • 2017-02-15
    • 1970-01-01
    • 1970-01-01
    • 2018-02-16
    • 1970-01-01
    • 1970-01-01
    • 2010-10-26
    • 1970-01-01
    • 2013-06-11
    相关资源
    最近更新 更多