【问题标题】:Checking UTF-8 data type 3-byte, or 4-byte Unicode检查 UTF-8 数据类型 3 字节或 4 字节 Unicode
【发布时间】:2013-02-05 12:41:04
【问题描述】:

在我的数据库中出现错误

com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column

我使用 Java 和 MySQL 5。我知道 4 字节 Unicode 在 Java 中是合法的,但在 MySQL 5 中是非法的,我认为这可能会导致我的问题,我想检查我的数据类型,所以这是我的问题: 如何检查我的 UTF-8 数据是 3 字节还是 4 字节 Unicode?​​p>

【问题讨论】:

  • 我建议先查看您的列数据类型长度限制和您尝试插入的数据的大小。如果您将 100K 字符插入到 VARCHAR 中,则没有编码有问题。
  • 我不认为 4 字节 UTF-8 编码的字符是这个问题的原因。更可能的原因是一个 n 字符的字符串,它在 UTF 时占用 m 个字节(带有 m > n) -8 编码,但应放入 VARCHAR(n)。
  • @Jon 我先检查了一下,这不是我已经解决的问题,但我仍然认为我将来会使用编码检查,谢谢大家的帮助
  • @JoachimSauer 仅供参考 MySQL 将 VARCHAR(n) CHARSET utf8 视为 N*3 字节结构,因此这不太可能是问题所在。问题很可能是 OP 只是试图插入太多数据。

标签: java mysql unicode utf-8 character-encoding


【解决方案1】:

UTF-8 将基本多语言平面中的所有内容(即 U+0000 到 U+FFFF 包括在内)编码为 1-3 个字节。因此,您只需要检查字符串中的所有内容是否 都在 BMP 中。

在 Java 中,这意味着检查任何 char(它是一个 UTF-16 代码单元)是高代理字符还是低代理字符,因为 Java 将使用代理对来编码非 BMP 字符:

public static boolean isEntirelyInBasicMultilingualPlane(String text) {
    for (int i = 0; i < text.length(); i++) {
        if (Character.isSurrogate(text.charAt(i))) {
            return false;
        }
    }
    return true;
}

【讨论】:

    【解决方案2】:

    如果您不想支持 BMP 以外的内容,您可以在将其交给 MySQL 之前删除这些字符:

    public static String withNonBmpStripped( String input ) {
        if( input == null ) throw new IllegalArgumentException("input");
        return input.replaceAll("[^\\u0000-\\uFFFF]", "");
    }
    

    如果你想支持 BMP 以外的东西,你需要 MySQL 5.5+ 并且你需要更改 utf8 的所有内容 到utf8mb4(排序规则、字符集...)。但是您还需要我的驱动程序对此的支持 不熟悉。在 Java 中处理这些字符也很痛苦,因为它们分布在 2 chars 因此在许多操作中需要特殊处理。

    【讨论】:

    • 这实际上效果不佳,因为正则表达式是在代码点级别而不是代码单元级别评估的。您需要匹配 \u0000-\uFFFF 范围之外的字符(请参阅我的答案)。
    • @jako512 这很令人惊讶,因为其他所有内容都涉及代码单元:我已经对其进行了编辑以使用完整的非 BMP 字符,但原始版本背后的意图是也删除不成对的代理项
    • 请注意,正则表达式可能会针对您的语言稍作调整。对于 PHP,请使用 preg_replace('/[^\x{0000}-\x{FFFF}]/u', '\x{FFFD}', $input);
    • \uF000 - \uFFFF utf8 序列仍然被您的正则表达式接受,但仅用于组成 4 字节字符。所以我使用较小的范围 \u0000 - \uEFFF 来删除所有 4 字节字符。
    【解决方案3】:

    found 在 java 中去除非 BMP 字符的最佳方法如下:

    inputString.replaceAll("[^\\u0000-\\uFFFF]", "\uFFFD");
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-05
      • 2015-10-08
      • 2014-03-17
      • 1970-01-01
      • 2012-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多