Java—从UTF-8和非UTF-8字符混合的字符串中精确计算60个字符

Java—从UTF-8和非UTF-8字符混合的字符串中精确计算60个字符,java,string,oracle,encoding,character-encoding,Java,String,Oracle,Encoding,Character Encoding,我有一个字符串,我想保存在一个只支持UTF8字符的数据库中。如果字符串大小>60个字符,我想截断它,只存储前60个字符。正在使用的Oracle数据库仅支持UTF-8字符 在Java中使用String.substring(0,59)返回60个字符,但当我将其保存到数据库中时,它会被拒绝,因为数据库声明字符串大于60个字符 是否有办法确定特定字符串是否包含非UTF8字符。我发现的一个选择是: 试试{ bytes = returnString.getBytes("UTF-8"); } c

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

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

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

    试试{

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

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


据我所知,您希望以编码的
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);
}

这是我的快速技巧:在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();
}

“我有一个字符串,它包含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字符序列。
truncateUtf8("e", 1) => "e"
truncateUtf8("ée", 1) => ""
truncateUtf8("ée", 2) => "é"
truncateUtf8("ée", 3) => "ée"