You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Perl写入MariaDB时decode_entities解码变音符号报编码错误

问题成因
  • Perl的字符串分两类:带UTF-8内部标记的Unicode字符串、无标记的原始字节串。你给DBI连接配置了mysql_enable_utf8mb4 => 1之后,DBD::mysql只会正确处理前者,会自动按utf8mb4编码转换后传给数据库;传入无标记的字节串时,驱动不会做任何编码转换,直接把原始字节发给数据库。
  • 脚本里直接写'Ärztin'能正常插入,是因为你的Perl脚本本身以UTF-8编码保存,Perl解析源码时会自动给这类字面量打上UTF-8标记,完全符合驱动的输入要求。
  • HTML::Entities的decode_entities默认返回ISO-8859-1(Latin-1)编码的原始字节串,不带UTF-8标记:比如ä解码后是单字节0xE4,和你报错信息里的\xE4rztin完全对应。这类单字节序列传给要求utf8mb4编码的列,自然触发非法字符串值报错。
  • 终端打印、写文件能正常显示,是因为你的终端默认编码兼容Latin-1,单字节变音符号刚好能被正确渲染,和字符串是否带UTF-8标记没有关系。
解决方案

优先选第一种改法,改动最小逻辑最顺:

  1. 配置decode_entities的实体处理回调,直接返回带UTF-8标记的Unicode字符串:
    use Encode qw(decode);
    # 所有解码出的字符统一转为UTF-8标记的Perl内部字符串
    $name = decode_entities($name, sub {
        decode('UTF-8', chr($_[0]), Encode::FB_CROAK)
    });
    
    处理后的$name和你脚本里写死的字符串形态完全一致,直接传入execute即可正常插入。
  2. 如果已经按默认方式调用了decode_entities拿到Latin-1字节串,手动转码即可:
    use Encode qw(decode);
    $name = decode_entities($name);
    # 把Latin-1编码的原始字节串解码为带UTF-8标记的Unicode字符串
    $name = decode('ISO-8859-1', $name, Encode::FB_CROAK);
    

注意事项

  • 不要直接用utf8::upgrade或者手动给字符串强制打UTF-8标记,会把Latin-1单字节错按UTF-8解析,最终存入数据库的会是乱码。
  • 调试时可以用utf8::is_utf8($name)确认字符串状态,只要传入execute的参数是带UTF-8标记的字符串,就不会再出现这类编码报错。

内容的提问来源于stack exchange,提问作者giordano

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 06:51:23