业务场景:
Oracle数据字符集UTF-8,字段类型为VARCHAR2。当插入字符串的字节长度超过4000时,就会报错。使用subString(0,2000)也会报错,因为数据库采用的字符编码不同每个汉字占用的字节数量也不一样。在数据库运行SQL语句:select * from v$nls_parameters t where t.PARAMETER='NLS_CHARACTERSET',返回当前数据库的字符集,如果value是GB2312,那么一个汉字占用2个字节,如果value是AL32UTF8,则一个汉字占用3个字节。所以又不能直接只截取1000长度,这就需要一个根据字节长度来截取字符串的方法。

package com.demo.util;

import lombok.SneakyThrows;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @Author zf
 * @ClassName SubStringUtils.java
 * @ProjectName Demo
 */
public class SubStringUtils {
    /**
     * 按字节长度截取字符串
     *
     * @param orgin       需要截取的字符串
     * @param blength     需要保留的字节长度
     * @param charsetName 编码,对于字符集为UTF-8的数据库,请指定编码为UTF-8;字符集为GBK的数据库,请指定编码GBK
     * @return 截取后的字符串
     * @throws UnsupportedEncodingException 不支持的字符编码
     */
    @SneakyThrows
    public static String sub(String orgin, int blength, String charsetName){
        return subList(orgin, blength, charsetName).get(0);
    }

    /**
     * 按字节长度分割字符串
     *
     * @param orgin       需要截取的字符串
     * @param blength     需要保留的字节长度
     * @param charsetName 编码,对于字符集为UTF-8的数据库,请指定编码为UTF-8;字符集为GBK的数据库,请指定编码GBK
     * @return 分割后的字符串
     * @throws UnsupportedEncodingException 不支持的字符编码
     */
    public static List<String> subList(String orgin, int blength, String charsetName) throws UnsupportedEncodingException {

        List<String> result = new ArrayList<>();
        int length;

        byte[] bs = orgin.getBytes(charsetName);
        while (bs.length > 0) {
            length = blength;
            if (length >= bs.length) {
                result.add(new String(bs, 0, bs.length, charsetName));
                break;
            }
            if ("UTF8".equals(charsetName.toUpperCase()) || "UTF-8".equals(charsetName.toUpperCase())) {
                // utf8 encoding
                // 0000 0000 - 0000 007F 0xxxxxxx
                // 0000 0080 - 0000 07FF 110xxxxx 10xxxxxx
                // 0000 0800 - 0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
                // 0001 0000 - 0010 FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
                while (length > 0) {
                    if ((bs[length] | 0x7F) == 0x7F) {
                        break;
                    }
                    if ((bs[length] & 0xC0) == 0xC0) {
                        break;
                    }
                /*
                if ((bs[length] & 0xE0) == 0xE0) {
                    break;
                }
                if ((bs[length] & 0xF0) == 0xF0) {
                    break;
                }
                */
                    length--;
                }
            } else if ("GBK".equals(charsetName.toUpperCase())) {
                boolean removLast = length % 2 == 1;
                for (int i = 0; i < length; i++) {
                    if ((bs[i] | 0x7F) == 0x7F) {
                        removLast = !removLast;
                    }
                }
                if (removLast) {
                    length--;
                }
            } else if ("UNICODE".equals(charsetName.toUpperCase())) {
                if (length % 2 == 1) {
                    length--;
                }
            } else if ("UTF-16".equals(charsetName.toUpperCase()) || "UTF16".equals(charsetName.toUpperCase())) {
                if (length % 2 == 1) {
                    length--;
                }
            } else if ("UTF-16BE".equals(charsetName.toUpperCase())) {
                if (length % 2 == 1) {
                    length--;
                }
            } else if ("UTF-16LE".equals(charsetName.toUpperCase())) {
                if (length % 2 == 1) {
                    length--;
                }
            }
            result.add(new String(bs, 0, length, charsetName));
            bs = Arrays.copyOfRange(bs, length, bs.length);
        }
        if (result.size() == 0) {
            result.add("");
        }
        return result;
    }
}
最后修改:2022 年 04 月 06 日
给我一点小钱钱也很高兴啦!o(* ̄▽ ̄*)ブ