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

package testchar;

public class TestChar2 {
public static void main(String[] args) {
String s = "\u0041\u00DF\u6771\ud801\uDC00";
for(int i = 0; i < s.length(); i++) {
System.out.println(s.charAt(i));
}
}
}

然后,得到了意料之外的结果:

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)

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

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

package testchar;

/**
* 正确遍历String
*
* @author yuncong
*
*/
public class TestChar { public static void main(String[] args) {
String s = "\u0041\u00DF\u6771\ud801\uDC00";
// 获得字符串中代码点的数量
int cpCount = s.codePointCount(0, s.length());
for (int i = 0; i < cpCount; i++) {
int index = s.offsetByCodePoints(0, i);
int cp = s.codePointAt(index);
if (!Character.isSupplementaryCodePoint(cp)) {
System.out.println((char) cp);
} else {
System.out.println(cp);
}
} System.out.println("-------------------"); for (int i = 0; i < s.length(); i++) {
int cp = s.codePointAt(i);
if (!Character.isSupplementaryCodePoint(cp)) {
System.out.println((char) cp);
} else {
System.out.println(cp);
i++;
}
} System.out.println("-------------------"); // 逆向遍历字符串
for(int i = s.length() - 1; i >= 0; i--) {
int cp = 0;
// 当i等于0的时候,只剩下一个代码单元,不可能是辅助字符
if (i == 0) {
cp = s.codePointAt(0);
System.out.println((char)cp);
} else {
// 只有在i大于0的时候才可以退,并且
// 因为剩下的代码单元大于2,所以接下
// 来访问的两个代码单元可能表示辅助
// 字符;
// 退一个代码单元
i--;
cp = s.codePointAt(i);
if (Character.isSupplementaryCodePoint(cp)) {
System.out.println(cp);
} else {
// 如果cp不是辅助字符,就回到遍历的正常位置
i++;
cp = s.codePointAt(i);
System.out.println((char)cp);
}
}
} } }

(天坑啊,博客中不能出现Java中的辅助字符)

java 遍历String的更多相关文章

  1. java 遍历map 方法 集合 五种的方法

    package com.jackey.topic; import java.util.ArrayList;import java.util.HashMap;import java.util.Itera ...

  2. java中String类型变量的赋值问题

    第一节 String类型的方法参数 运行下面这段代码,其结果是什么? package com.test; public class Example { String str = new String( ...

  3. java 遍历文件夹里的文件

    Java遍历文件夹的2种方法: A.不使用递归: import java.io.File; import java.util.LinkedList; public class FileSystem { ...

  4. JAVA 遍历文件夹下的所有文件

    JAVA 遍历文件夹下的所有文件(递归调用和非递归调用) 1.不使用递归的方法调用. public void traverseFolder1(String path) { int fileNum = ...

  5. java遍历树(深度遍历和广度遍历

    java遍历树如现有以下一颗树:A     B          B1               B11          B2               B22     C          C ...

  6. 解决spring mvc 上传报错,Field [] isn't an enum value,Failed to convert value of type 'java.lang.String[]' to required type '

    没有选择附件,但是点击上传按钮的时候会报错. 之前不选择文件,直接上传空文件是可以的,后来不知道改了什么就不行了. 错误信息: -- :: [http--] TRACE org.springframe ...

  7. java遍历Hashmap/Hashtable的几种方法

    一>java遍历Hashtabe: import java.util.Hashtable; import java.util.Set; public class HashTableTest { ...

  8. JAVA 遍历文件夹下的所有文件(递归调用和非递归调用)

    JAVA 遍历文件夹下的所有文件(递归调用和非递归调用) 1.不使用递归的方法调用. public void traverseFolder1(String path) { int fileNum = ...

  9. java 遍历List 和 Map的几种方法

    java遍历List 1.(性能最差) for(String tmp:list) { //System.out.println(tmp); } 2.(性能最好) for(int i = 0; i &l ...

随机推荐

  1. JMeter 八:录制脚本--使用Jmeter自带的代理服务器

    参考:http://jmeter.apache.org/usermanual/jmeter_proxy_step_by_step.pdf http://jmeter.apache.org/userma ...

  2. Unity3D研究院之DontDestroyOnLoad的坑

    http://www.xuanyusong.com/archives/2938 Unity中的一个方法DontDestroyOnLoad可以让某些游戏对象在切换场景的时候不是施放,听起来是一个非常好的 ...

  3. 算法笔记_105:蓝桥杯练习 算法提高 上帝造题五分钟(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 问题描述 第一分钟,上帝说:要有题.于是就有了L,Y,M,C 第二分钟,LYC说:要有向量.于是就有了长度为n写满随机整数的向量 第三分钟,YUHC ...

  4. raspberry pi install iceweasel

    sudo apt-get update sudo apt-get upgrade sudo apt-get install iceweasel

  5. Android源码-SignApk.java

    /* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Versi ...

  6. Getting started with Chrome Dev Editor

    转自:https://github.com/GoogleChrome/chromedeveditor/blob/master/doc/GettingStarted.md Installation In ...

  7. 常见SQL Server导入导出数据的几个工具

    摘自:http://www.cnblogs.com/chenxizhang/archive/2011/06/09/2076542.html 在我们的日常工作中,与数据库打交道的机会越来越多.这一篇文章 ...

  8. 用GDB命令PO(print-object)打印UIView的视图层级

    UIView有一个私有方法: recursiveDescription 这个方法可以显示出当前视图的详细层级,可以在代码中直接调用,也可以在GDB中调用,在GDB中调用时需要借助另一个GDB命令:pr ...

  9. 堆越界--coredump 在malloc函数里

    一,可执行程序分析: objdump -h xxx,可以看到程序内部各个段的内存分布,结果如下(部分):  26 .data         0000016c  0000000000879d20  0 ...

  10. mysql 常用功能

    一.备份 mysqldump [OPTIONS] database [tables] http://www.blogjava.net/Alpha/archive/2007/08/10/135694.h ...