用户操作
[即时聊天] [发私信] [加为好友]
曾巧ID:numenZQ
42207次访问,排名2821,好友0人,关注者0人。
numenZQ的文章
原创 29 篇
翻译 16 篇
转载 2 篇
评论 16 篇
最近评论
xh:不推荐修改web.xml,设置java_options更好
numenZQ:补充说明一点,使用java.util.zip包时,是以UTF-8编码格式读取的文件名,因此在中文windows操作系统(Windows操作系统默认字符集为:GBK)中使用时会导致文件名解析错误,因此需要使用org.apache.tools.zip.ZipEntry和 org.apache.tools.zip.ZipOutputStream类来解决这一问题。
numenZQ:这个是需要明确知道字符串的成分,该方法只是为了满足读取不同字符集相应字符串,还是以“多哈亚运会”为例:如果字符集为GBK,截取前6个字节,结果为:“多哈亚”;当字符集为UTF-8时,截取前6个字节,结果则为:“多哈”,这是因为GBK是双字节编码,而UTF-8是三字节变长编码,如果不分字符集来读取对应长度的字串,则会出现字串内容与预期不符,长度错误等问题。
lyazure:仔细看了你的代码,作用是从一个字符串中获取指定字节数的字符,不知道你要这么做的最终目的是用来做什么。除非明确知道字符串的成分,否则这种做法很难做到完美,比如你的代码中,假如出现要从“多哈亚运会”这样的字符串中截取7个字节,最终会截得3个字符。
Alexandre:ab8e44bc75204d49bf0c9fe68a2b2176 matura foto amatoriale
收藏
    相册
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 正确读取String中指定长度的中文字符收藏

    新一篇: ProGuard入门 | 旧一篇: JiBX初步

     作者:曾巧(numenzq)

        最近在与银行做一些应用,由于特定环境的原因,只能用GB2312字符编码,大家都知道,在GB2312编码下,一个中文是占两个字节的,而在java中,字符的处理是用的Unicode编码,所以一个中文只占一个字节。这样的话,我想从StringStringBuffer中取出想要的中文字符就会有一些问题。下面举个例子来说明吧。

     

    String str = "测试数据:正确读取String中指定长度的中文字符";

    System.out.println("content: " + str);

    System.out.println("length: " + str.length());

    System.out.println("substring(0, 6): " + str.substring(0, 6));

     

    Console:

    content: 测试数据:正确读取String中指定长度的中文字符

    length: 25

    substring(0, 6): 测试数据:正

    在上面的测试中,我们不难发现取出来的实际值(测试数据:正)与预期值(测试数)不一样。这正是上面所提到的问题,我们需要计算出这个偏移量(offset),也就是说把string里的每一个中文都当两个字节来算,公式为:偏移量 = 总偏移量 多出部分字符的偏移量。具体的代码如下:

    private static String getStringWithOffset(String data, int length,

        String charset) throws UnsupportedEncodingException {

     

        // 实际取出来的字符串,还存在偏移

        String tmpStr = data.substring(0, length);

     

    // 计算实际字符串的长度

        int tmpLength = tmpStr.getBytes(charset).length;

     

        // 如果实际长度是想要取的长度的两倍,说明实际取出的字符串全为中文字符,我的期望值正好为想要取的长度的一半

        if (length * 2 == tmpLength) {

           return tmpStr.substring(0, length / 2);

        }

     

        // 实际字符串比期望字符串多出的一部份字符串,存在偏移

        String leftString = tmpStr.substring(length * 2 - tmpLength, length);

     

        // 计算多出的字符串的长度

        int fixOffset = leftString.getBytes(charset).length;

     

        // 计算出我们向要的偏移量

        int offset = tmpLength - length - (fixOffset - leftString.length());

     

        // 期望的字符串

        return tmpStr.substring(0, length - offset);

    }

        如果你仔细分析上面的代码,或则拿实际的数据来测试的话,可能会有StringIndexOutOfBoundsException异常。还是举个例子来说明出现这个异常的原因吧。假使我们的测试数据是"多哈亚运会"如果是GB2312的编码,这五个字符占10位,而在String里只有五位,如果我们只想取前四个字符,应该是substring.(0, 8);这当然会出现上面提到的异常啦。为了解决这个问题,我们可以不用偏移量这个概念来取数据,而是用字节数组来完成这件事,具体代码如下:

    private static String getStringWithByteArray(String data, int length,

    String charset) throws UnsupportedEncodingException {

     

    // 期望值

        byte[] result = new byte[length];

        // 实际内容

        byte[] content = null;

     

        // 如果实际值大于想要获得字符串的长度,则内容只取想要的长度相应的位数,否则取所有的内容

        if (data.length() > length) {

           content = data.substring(0, length).getBytes(charset);

        } else {

           content = data.toString().getBytes(charset);

        }

     

        // 如果字节数组的长度都小于想要的长度(数据不够取), 错误处理。

        if (content.length < length) {

           // TODO error

           throw new IndexOutOfBoundsException();

        }

     

        // 将要取的数据给期望值

        System.arraycopy(content, 0, result, 0, length);

     

        // 返回期望值

        return new String(result, charset);

    }

    这样修改后,我们就可以放心的使用了,但是这个方法还不能通用,你从代码中也看到了,取子串时,都是从头开始取的,如果你想从特定位置开始取子串的话,只有多一个startPosition参数了,这个就需要你自己修改了:P;如果有问题或更好的想法,请与我联系。

    发表于 @ 2006年12月10日 20:24:00|评论(loading...)|编辑

    新一篇: ProGuard入门 | 旧一篇: JiBX初步

    评论

    #flushtime 发表于2006-12-18 16:57:37  IP: 221.238.245.*
    我没有太仔细看楼主的代码,不过我认为楼主的一些理解存在偏差. 比如"而在java中,字符的处理是用的Unicode编码,所以一个中文只占一个字节。" 事实上在Unicode中每个字符都占用两个字节,也就是一个char! 下面是我写的代码,如有错误,望指正. [code] /** *gb2312字符处理测试函数 *@author Eastsun */ public class StrTest{ public static void main(String[] args){ String str ="测试数据:正确读取String中指定长度的中文字符"; StringWork work =new StringWork(str); System.out.println("content: " + work); System.out.println("length: " + work.length()); System.out.println("substring(0, 6): " + work.substring(0, 6)); } } /** *字符处理类,能得到字符在gb2312下的编码,以及在gb2312意义下的子串 */ class StringWork{ private byte[] buf; public StringWork(String str){ try{ buf =str.getBytes("gb2312"); //使用gb2312字符集将此 String 解码为字节序列 }catch(Exception e){} //do nothing } public String substring(int start,int end){ String result =null; try{ result =new String(buf,start,end-start,"gb2312"); }catch(Exception e){} //do nothing return result; } public String toString(){ return substring(0,length()); } public int length(){ return buf.length; } } [/code]
    #flushtime 发表于2006-12-18 17:00:34  IP: 221.238.245.*
    晕... 咋代码贴上去就变样了.
    #numenZQ 发表于2006-12-19 22:51:49  IP: 221.5.194.*
    flushtime,我在描述上是有问题,谢谢指正,应该说成是一个字符哈,而不是一个字节。
    #numenZQ 发表于2006-12-19 23:00:13  IP: 221.5.194.*
    另外,你贴的那段代码看起有点痛苦,你这样做是没问题的,也就是我说的用bytearray的方法来处理,其实你可以提一个更好的工具类出来,以后就可以通用了:)
    #lyazure 发表于2007-09-10 14:35:58  IP: 219.136.9.*
    仔细看了你的代码,作用是从一个字符串中获取指定字节数的字符,不知道你要这么做的最终目的是用来做什么。除非明确知道字符串的成分,否则这种做法很难做到完美,比如你的代码中,假如出现要从“多哈亚运会”这样的字符串中截取7个字节,最终会截得3个字符。
    #numenZQ 发表于2007-09-12 16:31:11  IP: 221.130.180.*
    这个是需要明确知道字符串的成分,该方法只是为了满足读取不同字符集相应字符串,还是以“多哈亚运会”为例:如果字符集为GBK,截取前6个字节,结果为:“多哈亚”;当字符集为UTF-8时,截取前6个字节,结果则为:“多哈”,这是因为GBK是双字节编码,而UTF-8是三字节变长编码,如果不分字符集来读取对应长度的字串,则会出现字串内容与预期不符,长度错误等问题。
    发表评论  


    登录
    Csdn Blog version 3.1a
    Copyright © numenzq