人口信息生僻字合法性校验


人口信息生僻字合法性校验

随着反洗钱等监管要求,对客户信息的准确性要求越来越高,大量客户需要补全个人身份信息,以往未重视的姓名生僻字问题又再一次被提出需尽快解决。生僻字问题一直存在,从“龙天”到“艹频”,生僻字问题主要涉及生僻字的输入、输出、通信传输、数据存储、信息打印等。

市面上针对生僻字也有许多解决方案,诸如专用的生僻字输入法或云字库等,在这里不做细谈。

本文章主要介绍在使用 GB18030 编码字库时,对扩展汉字的合法性校验。

合法性校验编码范围如下:

CJK基本(基本+):[4E00-9FFF] ---- 10进制区间:[19968-40959]
CJK扩展A:[3400-4DBF] ---- 10进制区间:[13312-19903]
CJK兼容:[E000-FAFF] ---- 10进制区间:[57344-64255]
CJK扩展B:[20000-2A6D6] ---- 10进制区间:[131072-173782]
CJK扩展C:[2A700-2B734] ---- 10进制区间:[173824-177972]
CJK扩展D:[2B740-2B81D] ---- 10进制区间:[177984-178205]
CJK扩展E:[2B820-2CEAF] ---- 10进制区间:[178208-183983]
CJK扩展F:[2CEB0-2EBE0] ---- 10进制区间:[183984-191456]
CJK扩展G:[30000-3134A] ---- 10进制区间:[196608-201546]

字符串是 GBK 编码时,一个汉字占用两个字节, GB18030 编码存在生僻字使用 4 字节的编码方式,转换 Unicode 编码如下:

public class CheckChinese {
    public static void main(String[] args) {
        String str1 = "复";
        String str2 = "复𬟁";
        System.out.println(cnToUnicode(str1));
        System.out.println(cnToUnicode(str2));
    }

    /*
    * 中文转Unicode
    * */
    public static String cnToUnicode(String cn){
        char[] chars = cn.toCharArray();
        String returnStr = "";
        for (int i = 0; i < chars.length; i++){
            returnStr += "\\u" + Integer.toString(chars[i], 16);
        }
        return returnStr;
    }
}

输出:

\u590d
\u590d\ud871\udfc1

Process finished with exit code 0

传统 GBK 汉字合法性校验正则表达式不再适用:

/^[\u4e00-\u9fa5]+$/i;

CheckCNFormat()

我采用将16进制编码转换成10进制编码比较生僻字是否在合法性校验范围内来判断输入字符串是否合法,方法如下:

public class CheckCNFormat {
    public static void main(String[] args) {
        boolean flag;
        String fonts = "测试㛓𬎆";
        flag = isCNFormat(fonts);
        System.out.println("-------------------------------------------");
        if(flag){
            System.out.println("汉字合法性校验通过");
        } else {
            System.out.println("汉字合法性校验不通过");
        }
    }

    /*
     * 汉字合法性校验
     * */
    public static boolean isCNFormat(String str) {
        boolean flag = true;
        //计算字符串字节长度
        int cpcount = str.codePointCount(0, str.length());
        //offsetByCodePoints(int ,int )方法返回String中从给定的index处偏移codePointOffset个代码点的索引。
        int firCodeIndex = str.offsetByCodePoints(0, 0);//String起点索引
        int lstCodeIndex = str.offsetByCodePoints(0, cpcount - 1);//String终点索引
        //java.lang.Character.isSupplementaryCodePoint(int codePoint)是java中的内置方法,用于确定指定字符(Unicode代码点)是否在补充字符范围内。
        for (int index = firCodeIndex; index <= lstCodeIndex; index += ((Character.isSupplementaryCodePoint(str.codePointAt(index))) ? 2 : 1)) {
            String reg = Integer.toHexString(str.codePointAt(index));
            int i = Integer.parseInt(reg, 16);
            System.out.println("字符:【" + String.valueOf(Character.toChars(str.codePointAt(index))) + "】--10进制:" + i);
            if (!RangeJudge(i)) {
                System.out.println("字符:【" + String.valueOf(Character.toChars(str.codePointAt(index))) + "】--16进制编码:" + reg + " -- " + "合法性校验不通过");
                flag = false;
                break;
            } else {
                System.out.println("字符:【" + String.valueOf(Character.toChars(str.codePointAt(index))) + "】--16进制编码:" + reg + " -- " + "合法性校验通过");
                continue;
            }
        }
        return flag;
    }

    /*
     * 汉字区间判断,以10进制比较
     *
     * CJK基本(基本+):[4E00-9FFF] ---- 10进制区间:[19968-40959]
     * CJK扩展A:[3400-4DBF] ---- 10进制区间:[13312-19903]
     * CJK兼容:[E000-FAFF] ---- 10进制区间:[57344-64255]
     * CJK扩展B:[20000-2A6D6] ---- 10进制区间:[131072-173782]
     * CJK扩展C:[2A700-2B734] ---- 10进制区间:[173824-177972]
     * CJK扩展D:[2B740-2B81D] ---- 10进制区间:[177984-178205]
     * CJK扩展E:[2B820-2CEAF] ---- 10进制区间:[178208-183983]
     * CJK扩展F:[2CEB0-2EBE0] ---- 10进制区间:[183984-191456]
     * CJK扩展G:[30000-3134A] ---- 10进制区间:[196608-201546]
     *
     * */
    public static boolean RangeJudge(int reg) {
        boolean flag;
        if (reg >= 13312 && reg <= 19903) {
            flag = true;
        } else if (reg >= 19968 && reg <= 40959) {
            flag = true;
        } else if (reg >= 57344 && reg <= 64255) {
            flag = true;
        } else if (reg >= 131072 && reg <= 173782) {
            flag = true;
        } else if (reg >= 173824 && reg <= 177972){
            flag = true;
        } else if (reg >= 177984 && reg <= 178205){
            flag = true;
        } else if (reg >= 178208 && reg <= 183983){
            flag = true;
        } else if (reg >= 183984 && reg <= 191456){
            flag = true;
        } else if (reg >= 196608 && reg <= 201546){
            flag = true;
        } else {
            flag = false;
        }
        return flag;
    }
}

验证后如下,当字符串中含有非汉字字符时,即合法性校验不通过:

字符:【𦰡】--10进制:158753
CJK扩展B-[131072-173782]
字符:【𦰡】--16进制编码:26c21 -- 合法性校验通过
--------------------------------------
字符:【𬎆】--10进制:181126
CJK扩展E-[178208-183983]
字符:【𬎆】--16进制编码:2c386 -- 合法性校验通过
--------------------------------------
字符:【测】--10进制:27979
CJK基本(基本+)-[19968-40959]
字符:【测】--16进制编码:6d4b -- 合法性校验通过
--------------------------------------
字符:【试】--10进制:35797
CJK基本(基本+)-[19968-40959]
字符:【试】--16进制编码:8bd5 -- 合法性校验通过
--------------------------------------

Character.isSupplementaryCodePoint()

1、语法

public static boolean isSupplementaryCodePoint(int codePoint)

2、参数

codePoint:进行测试的字符(Unicode代码点)

3、返回值

如果指定的代码点是在MIN_SUPPLEMENTARY_CODE_POINT和MAX_CODE_POINT(含)之间此方法返回true,否则返回 false


  目录