字符串的遍历

Java字符串是一系列的Unicode字符序列,但是,它却常常被误认为是char序列。于是,我们经常这样来遍历字符串:

[java]  view plain copy
  1. package testchar;  
  2.   
  3. public class TestChar2 {  
  4.     public static void main(String[] args) {  
  5.         String s = "\u0041\u00DF\u6771\ud801\uDC00";  
  6.         for(int i = 0; i < s.length(); i++) {  
  7.             System.out.println(s.charAt(i));  
  8.         }  
  9.     }  
  10. }  
然后,得到了意料之外的结果:

A

ß

?

?

之所以会这样,是因为Unicode字符和Java的char类型不能等同起来。实际上,Java中的char类型能表示的字符只是Unicode字符的子集,因为char只有16位,也就是说,它只能表示65536(2的16次方)个字符,但实际的Unicode字符数超过这个数字。在Java中,用UTF-16编码char和String中的字符,一个字符对应的编码值被称为一个代码点。有的代码点用16位编码,被称为一个代码单元,像char表示的那些字符;有的代码点用32位编码,也就是用两个连续的代码单元编码,如上文中的\ud801\uDC00。其实,我们遍历一个字符串,遍历的是这个字符串中所有代码点,而

s.length()

返回的是字符串s中代码单元的个数。当i对应的代码单元只是一个32位代码点的一部分时,

s.charAt(i)

也就不能像我们希望的那样工作了。

下面给出了几种正确遍历一个字符串的方法:

[java]  view plain copy
  1. package testchar;  
  2.   
  3. /** 
  4.  * 正确遍历String 
  5.  *  
  6.  * @author yuncong 
  7.  *  
  8.  */  
  9. public class TestChar {  
  10.   
  11.     public static void main(String[] args) {  
  12.         String s = "\u0041\u00DF\u6771\ud801\uDC00";  
  13.         // 获得字符串中代码点的数量  
  14.         int cpCount = s.codePointCount(0, s.length());  
  15.         for (int i = 0; i < cpCount; i++) {  
  16.             int index = s.offsetByCodePoints(0, i);  
  17.             int cp = s.codePointAt(index);  
  18.             if (!Character.isSupplementaryCodePoint(cp)) {  
  19.                 System.out.println((char) cp);  
  20.             } else {  
  21.                 System.out.println(cp);  
  22.             }  
  23.         }  
  24.   
  25.         System.out.println("-------------------");  
  26.   
  27.         for (int i = 0; i < s.length(); i++) {  
  28.             int cp = s.codePointAt(i);  
  29.             if (!Character.isSupplementaryCodePoint(cp)) {  
  30.                 System.out.println((char) cp);  
  31.             } else {  
  32.                 System.out.println(cp);  
  33.                 i++;  
  34.             }  
  35.         }  
  36.           
  37.         System.out.println("-------------------");  
  38.           
  39.         // 逆向遍历字符串  
  40.         for(int i = s.length() - 1; i >= 0; i--) {  
  41.             int cp = 0;  
  42.             // 当i等于0的时候,只剩下一个代码单元,不可能是辅助字符  
  43.             if (i == 0) {  
  44.                 cp = s.codePointAt(0);  
  45.                 System.out.println((char)cp);  
  46.             } else {  
  47.                 // 只有在i大于0的时候才可以退,并且  
  48.                 // 因为剩下的代码单元大于2,所以接下  
  49.                 // 来访问的两个代码单元可能表示辅助  
  50.                 // 字符;  
  51.                 // 退一个代码单元  
  52.                 i--;  
  53.                 cp = s.codePointAt(i);  
  54.                 if (Character.isSupplementaryCodePoint(cp)) {  
  55.                     System.out.println(cp);  
  56.                 } else {  
  57.                     // 如果cp不是辅助字符,就回到遍历的正常位置  
  58.                     i++;  
  59.                     cp = s.codePointAt(i);  
  60.                     System.out.println((char)cp);  
  61.                 }  
  62.             }  
  63.         }  
  64.           
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值