【问题标题】:Java - Count exactly 60 characters from a string with a mixture of UTF-8 and non UTF-8 charactersJava - 从混合了 UTF-8 和非 UTF-8 字符的字符串中精确计算 60 个字符
【发布时间】:2014-03-12 23:01:51
【问题描述】:

我有一个字符串,我想将它保存在仅支持 UTF8 字符的数据库中。如果字符串大小大于 60 个字符,我想截断它并只存储前 60 个字符。使用中的 Oracle 数据库仅支持 UTF-8 字符。

在 Java 中使用 String.substring(0,59) 返回 60 个字符,但是当我将其保存在数据库中时,它会被拒绝,因为数据库声称该字符串大于 60 个字符。

  • 有没有办法找出特定字符串是否包含非 UTF8 字符。我发现的一个选项是:

    try {

        bytes = returnString.getBytes("UTF-8");
    
    
    } catch (UnsupportedEncodingException e) {
        // Do something
    

    }

  • 有没有办法可以将其截断为 x 个字符(数据丢失不是问题),并确保在数据库中保存时只保存 x 个字符。例如,如果我有字符串 §8§8§8§8§8§8§8 并且我说截断并只保存 5 个字符,它应该只保存 §8§

【问题讨论】:

  • "我有一个字符串,其中包含 UTF-8 和非 UTF-8 字符的混合。"没有这样的事情。 Java中的所有个字符都存储为UTF-16,每个有效字符都可以用UTF-8表示。非常不清楚您的实际意思。
  • 好吧,这就是它们在 Java 中的表示方式,但是当我将字符串存储在 Oracle 中时,它不再是 UTF-16(如果 Oracle 中配置的字符集是 UTF-8)对吗?
  • 但这并不意味着您的问题有任何意义。真的没有“UTF-8 字符”这样的东西。 UTF-8 是一种编码,仅此而已。
  • 你应该决定是“70个字符”还是“60个字符”;两者都在您的问题中出现两次。我在回答中使用了60……
  • @ziggy:例如,如果您的字符串仅包含代理对的一半。那将是一个 UTF-16 代码单元序列,实际上并不代表有效的 Unicode 字符序列。

标签: java string oracle encoding character-encoding


【解决方案1】:

据我了解,您希望限制 String 的长度,使编码的 UTF-8 表示不超过 60 个字节。你可以这样做:

String s=…;
CharsetEncoder enc=StandardCharsets.UTF_8.newEncoder();
ByteBuffer bb=ByteBuffer.allocate(60);// note the limit
CharBuffer cb = CharBuffer.wrap(s);
CoderResult r = enc.encode(cb, bb, true);
if(r.isOverflow()) {
    System.out.println(s+" is too long for "
                      +bb.capacity()+" "+enc.charset()+" bytes");
    s=cb.flip().toString();
    System.out.println("truncated to "+s);
}

【讨论】:

    【解决方案2】:

    这是我的小窍门:将字符串截断为 UTF-8 编码中给定字节数的函数:

    public static String truncateUtf8(String original, int byteCount) {
        if (original.length() * 3 <= byteCount) {
            return original;
        }
        StringBuilder sb = new StringBuilder();
        int count = 0;
        for (int i = 0; i < original.length(); i++) {
            char c = original.charAt(i);
            int newCount;
            if (c <= 0x7f) newCount = count + 1;
            else if (c <= 0x7ff) newCount = count + 2;
            else newCount = count + 3;
            if (newCount > byteCount) {
                break;
            }
            count = newCount;
            sb.append(c);
        }
        return sb.toString();
    }
    

    对于 BMP 之外的字符,它不能按预期工作 - 将它们计为 6 个字节而不是 4 个字节。它还可能破坏字素簇。但对于大多数简单的任务来说应该没问题。

    truncateUtf8("e", 1) => "e"
    truncateUtf8("ée", 1) => ""
    truncateUtf8("ée", 2) => "é"
    truncateUtf8("ée", 3) => "ée"
    

    【讨论】:

      猜你喜欢
      • 2023-03-27
      • 2011-09-30
      • 2013-11-17
      • 1970-01-01
      • 1970-01-01
      • 2017-06-18
      • 2022-11-12
      • 1970-01-01
      • 2018-01-23
      相关资源
      最近更新 更多