正确读取String中指定长度的中文字符

本文介绍了一种在Java中处理GB2312编码下中文字符的方法,通过计算偏移量和使用字节数组来正确截取指定长度的中文字符串。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 作者:曾巧(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;如果有问题或更好的想法,请与我联系。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值