字符串与字符集

因为项目中cics中用到报文编码集转换处理,所以测试了一下编码集这方面的内部转换机制,时间问题也没有彻底弄懂,先乱七八糟写一些,回头再整理,同时也抛砖引玉。

先看一段代码

    public static  int getByteLeng(String s,final String incoding) throws UnsupportedEncodingException{
        System.out.println("--------------"+incoding+"["+s+"]--------------");
        byte b[]=s.getBytes(incoding);
        System.out.println(Arrays.toString(b));
        System.out.print("codePoint:");
        for (int i = 0; i < s.length(); i++) {
            System.out.print(s.codePointAt(i)+" | ");
        }
        System.out.println();
        return b.length;
    }

测试如下

    public static void main(String args[]) throws UnsupportedEncodingException{
//        String str =new String( "一二三四五六七八九十二");
        String str =new String( "一二三四1234");
        System.out.println("Unicode length="+CICSUtil.getByteLeng(str,"Unicode"));
        System.out.println("utf-16 length="+CICSUtil.getByteLeng(str,"utf-16"));
        System.out.println("utf-8 length="+CICSUtil.getByteLeng(str,"utf-8"));
        System.out.println("GBK length="+CICSUtil.getByteLeng(str,"GBK"));
        System.out.println("GBK length="+CICSUtil.getByteLeng(str,"gb2312"));

}

输出:

--------------Unicode[一二三四1234]--------------
[-1, -2, 0, 78, -116, 78, 9, 78, -37, 86, 49, 0, 50, 0, 51, 0, 52, 0]
codePoint:19968 | 20108 | 19977 | 22235 | 49 | 50 | 51 | 52 |
Unicode length=18
--------------utf-16[一二三四1234]--------------
[-2, -1, 78, 0, 78, -116, 78, 9, 86, -37, 0, 49, 0, 50, 0, 51, 0, 52]
codePoint:19968 | 20108 | 19977 | 22235 | 49 | 50 | 51 | 52 |
utf-16 length=18
--------------utf-8[一二三四1234]--------------
[-28, -72, -128, -28, -70, -116, -28, -72, -119, -27, -101, -101, 49, 50, 51, 52]
codePoint:19968 | 20108 | 19977 | 22235 | 49 | 50 | 51 | 52 |
utf-8 length=16
--------------GBK[一二三四1234]--------------
[-46, -69, -74, -2, -56, -3, -53, -60, 49, 50, 51, 52]
codePoint:19968 | 20108 | 19977 | 22235 | 49 | 50 | 51 | 52 |
GBK length=12
--------------gb2312[一二三四1234]--------------
[-46, -69, -74, -2, -56, -3, -53, -60, 49, 50, 51, 52]
codePoint:19968 | 20108 | 19977 | 22235 | 49 | 50 | 51 | 52 |
GBK length=12
根据输出可以看出,不同编码集转换为字节流以后差别还是挺大的,Unicode与utf-16编码方式类似,属于定长编码集,前面两位都是用来标示高低位,后面才是对字符的编码集,无论对于汉字或者字母都是转换为两位byte,只不过字母字符实际上只有一位,在另一位就会补0站位,Unicode是在低位补0,而utf-16却是在高位补0,其他转换算法相同;

utf-8编码稍微有些特殊,属于变长编码集,他会将汉字字符和字母字符按照不同的方式解码,汉字被解成3个byte而字母字符直接就对应的ascii码或者叫hash码。

gbk与gb232实际上就是同一种编码,也属于变长编码集,不过他将汉字解码成2位byte,字母字符直接就对应的ascii码。

java5 开始引入了codepoint,上面也打印出来了,不过对于汉字编码算法还是没有看懂,如果哪位朋友知道提醒我一下。

 

对编码方式搞明白了,处理就简单了,最常见的就是截取字串问题。这里一个思路是,把字符转换为byte[],不管用那种编码集,处理完后再用这种编码集转变回来,就不会有问题,不同的编码集,截取处理方式是不相同的,但都能达到同样截取的目的。

如果你取n个char,什么也不用考虑,直接用substring函数就搞定,但如果涉及通讯方面,底层一般都是按照byte流来传递的,这就难免要用到byte []处理

 

给个例子,按gbk编码方式来处理的

    /**
     * 按位拷贝字符串
     * @param s 要截取的字符串
     * @param sindex 开始位索引
     * @param eindex 结束位索引,这一位是不包括在内的
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String substring(String origin, int sindex, int eindex ) throws UnsupportedEncodingException {
        String encoding="GBK";
        if (origin == null || origin.equals(""))
            return "";
        int len = eindex - sindex;
        byte[] strByte = new byte[len];
        System.arraycopy(origin.getBytes(encoding), sindex, strByte, 0, len);
        int count = 0;
        for (int i = 0; i < len; i++) {
            int value = (int) strByte[i];
            if (value < 0) {
                count++;
            }
        }
        if (count % 2 != 0) {
            len = (len == 1) ? ++len : --len;
        }
        return new String(strByte, 0, len,encoding);
    }

用Unicode编码集处理也是同样效果
     public static String Substring(String s, int length) throws UnsupportedEncodingException  {
        byte[] bytes = s.getBytes("Unicode");
        int n = 0; 
        int i = 2; 
        for (; i < bytes.length && n < length; i++) {
            if (i % 2 == 1) {
                n++; 
            } else {
                if (bytes[i] != 0) {
                    n++;
                }
            }
        }
        if (i % 2 == 1){
            if (bytes[i - 1] != 0)
                i = i - 1;
            else
                i = i + 1;
        }
        return new String(bytes, 0, i, "Unicode");
    } 

这个方法只能从头截取,没有上面那个灵活,不过也能说明问题,如果有这个需求,修改一些也很容易。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值