背景:oracle数据库。储存编码UTF-8.
需求:如果字段超出数据库字段长度,那么截取字符串后储存到数据库中。
字段长 4000
最开始计划直接使用java String.subString,然后一想,好像不对,汉字长大概是占3个字节。如果有汉字的话,肯定超长了。然后就找了找有没有工具类可以直接截取数据库长度的方法,没有找到。
只能自己写了。网上找了找UTF8相关文章,发现UTF8规则如下。
1字节:0xxxxxxx
2字节:110xxxxx 10xxxxxx
3字节:1110xxxx 10xxxxxx 10xxxxxx
4字节:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
5字节:111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
6字节:1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
程序想法,找到字符串一共占多少字节,
然后从最大限制长度找到最大的合法字符。例如本例子就是4000.
如果是0xxxxxxx,直接返回4000.
如果是10xxxxxx ,则长度-1,
如果是110xxxxx,则规则长度是当前长度+1,然后跟限制长度比较。
如果是1110xxxx ,则规则长度是当前长度+2,然后跟限制长度比较。等等。。。。
代码如下,(ps:代码比较乱,不漂亮。) 经过测试好像没问题,有问题再改。
package com.test;
import java.nio.charset.Charset;
import java.util.Arrays;
public class TruncateUTF {
public static void main(String[] args) {
String test = "1你好你好测试测试。123123";
int length = test.getBytes(Charset.forName("UTF-8")).length;
for (int i = 1; i<=length+10; i++){
System.out.printf("length is %d, sub string is %s \n", i , truncateUTFString(test, i));
}
}
public static String truncateUTFString(String str, int length){
byte bytes[] = str.getBytes(Charset.forName("UTF-8"));
int l = getMaxAvailableLength(str, length);
System.out.printf("the length is %s , the available length is %s \n", length, l );
return new String (Arrays.copyOfRange(bytes, 0, l), Charset.forName("UTF-8"));
}
public static int getMaxAvailableLength(String str, int length){
byte [] bytes = str.getBytes(Charset.forName("UTF-8"));
if (bytes.length <= length){
return bytes.length;
}
int maxLength = length;
while(length > 0){
if (bytes[length] >= (byte)0x00 && bytes[length] <= (byte)0x7f){
return getMaxLength(maxLength, length , 0);
}else if (bytes[length] >= (byte)0x80 && bytes[length] <= (byte)0xBF){
length --;
continue ;
}else if (bytes[length] >= (byte)0xC0 && bytes[length] <= (byte)0xDF){
return getMaxLength(maxLength, length , 1);
}else if (bytes[length] >= (byte)0xE0 && bytes[length] <= (byte)0xEF){
return getMaxLength(maxLength, length , 2);
}else if (bytes[length] >= (byte)0xF0 && bytes[length] <= (byte)0xF7){
return getMaxLength(maxLength, length , 3);
}else if (bytes[length] >= (byte)0xF8 && bytes[length] <= (byte)0xFB){
return getMaxLength(maxLength, length , 4);
}else if (bytes[length] >= (byte)0xFC && bytes[length] <= (byte)0xFD){
return getMaxLength(maxLength, length , 5);
}
}
return 0;
}
public static int getMaxLength(int maxLength, int length, int gap){
if (length + gap >= maxLength){
return length ;
} else {
return maxLength;
}
}
/*
* 1字节:0xxxxxxx 00 7f
2字节:110xxxxx 10xxxxxx c0 df
3字节:1110xxxx 10xxxxxx 10xxxxxx e0 ef
4字节:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx f0 f7
5字节:111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx f8 fb
6字节:1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx fc fd
*/
}