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. bootstrap的两种在input框后面增加一个图标的方式

    第一种: <div class="input-group"> <div class="input-icon-group"> <di ...

  2. 《Javascript权威指南》学习笔记之十九--HTML5 DOM新标准---处理文档元信息和管理交互能力

    一.了解DOM 1.DOM是Document Object Model的缩写,即文档对象类型,是文档在内存中的表示形式,是一个应用程序接口,定义了文档的逻辑结构以及一套訪问和处理文档的方法. 2.HT ...

  3. Timer使用

    1. Timer简介 Timer是jdk中提供的一个定时器工具,使用的时候会在主线程之外起一个单独的线程执行指定的计划任务,可以指定执行一次或者反复执行多次. 通过创建Timer对象,然后调用Time ...

  4. cookie存中文

    cookie存取: 存: Cookie cookie = new Cookie("title",URLEncoder.encode("标题","utf ...

  5. hibernate的配置, 增删改查

    路径:查找路径 实际上都是查找编译后的对应的路径,在bin文件夹中总 增删改必须开启事务才行 hibernate加载文件的两种方式 configure 1.引包 antlr-2.7.6.jar bac ...

  6. Hibernate关联关系(二) Cascade级联

    1.cascade定义的是关系两端对象到对象的级联关系:而inverse定义的是关系和对象的级联关系. all : 所有情况下均进行关联操作.  none:所有情况下均不进行关联操作.这是默认值.  ...

  7. 0xffff0000颜色表示

    0xffff0000表红色,意思是: A:ff=255 R:ff=255 G:00=0 B:00=0 可如下将(255,0,0,255)转成0xffff0000并输出: inline DWORD RG ...

  8. 可能是最通俗易懂的 Java 位操作运算讲解

    https://blog.csdn.net/briblue/article/details/70296326

  9. 【转载】Oracle数据字典详解

    转自:http://czmmiao.iteye.com/blog/1258462 Oracle数据字典概述 数据库是数据的集合,数据库维护和管理这用户的数据,那么这些用户数据表都存在哪里,用户的信息是 ...

  10. 多线程-ThreadLocal,InheritableThreadLocal

    ThreadLocal 变量值得共享可以使用public static变量的形式,所有的线程都使用同一个public static变量.如果想实现每一个线程都有自己的共享变量该如何解决呢?JDK中提供 ...