字符串的遍历

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.           
C语言中字符串遍历有多种方法,以下为你详细介绍: ### 通过下标访问遍历 字符串遍历方式和数组一样,可通过下标进行访问,使用循环对每个内存空间进行访问,以终止标识符为结束条件。示例代码如下: ```c #include <stdio.h> #include <string.h> int main() { char str1[6] = "world"; for (int i = 0; i < strlen(str1); i++) { printf("%c ", str1[i]); } printf("\n"); return 0; } ``` 该代码中,使用`for`循环和`strlen`函数获取字符串长度,通过下标`i`逐个访问字符串中的字符并打印输出[^1]。 ### 遍历字符串数组 #### 直接遍历 ```c #include <stdio.h> int main(void) { int i; char cs[][6] = {"VV", "cat", "2020"}; for (i = 0; i < 3; i++) { printf("cs[%d] = \"%s\"\n", i, cs[i]); } return 0; } ``` 上述代码直接使用`for`循环遍历字符串数组,输出每个字符串元素[^2]。 #### 使用函数遍历字符串数组 ```c #include <stdio.h> void traversal(const char s[][6], int n) { int i; for (i = 0; i < n; i++) { printf("s[%d] = \"%s\"\n", i, s[i]); } } int main(void) { char cs[][6] = {"VV", "cat", "2020"}; traversal(cs, 3); return 0; } ``` 此代码定义了`traversal`函数来遍历字符串数组,在`main`函数中调用该函数完成遍历。需注意,在接收二维数组的形参的声明中,只有第一维的数组元素可以省略,如`void traversal(const char s[][6], int n)`是正确的声明方式,而`void traversal(const char s[][], int n)`是不正确的声明方式[^2]。 #### 使用函数遍历字符串每一个字符 ```c #include <stdio.h> void traversal(const char s[][6], int n) { int i; for(i = 0; i < n; i++) { int j = 0; printf("s[%d] = \"", i); while(s[i][j]) { putchar(s[i][j++]); } puts("\""); } } int main(void) { char cs[][6] = {"VV", "cat", "2020"}; traversal(cs, 3); return 0; } ``` 该代码定义的`traversal`函数使用`while`循环遍历字符串数组中的每个字符并输出,以字符串的终止符`'\0'`作为结束条件[^2]。 ### 指针遍历字符串 ```c #include <stdio.h> int main() { char *str = "hello"; while (*str) { printf("%c ", *str); str++; } printf("\n"); return 0; } ``` 上述代码使用字符指针`str`遍历字符串,通过指针的移动逐个访问字符,当指针指向的字符为`'\0'`时结束遍历。当重新为字符指针初始化一个字符串时,并不是修改原来的字符串,因为原来的字符串数据是不可更改的,而是重新创建了一个字符串,把这个新的字符串的地址赋给指针,建议使用字符指针来存储字符串数据,其优势是长度任意[^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值