第十三章 字符串

本文详细探讨了Java中的字符串操作,包括不可变的String类、递归问题、格式化输出、正则表达式的使用及扫描输入的技术。通过实例展示了如何使用StringBuilder、format方法、Formatter类和Scanner类,以及正则表达式的创建、匹配、分割和替换操作,旨在提高开发者对Java字符串处理能力的理解。
2013年8月1日 星期四 21时05分59秒

第十三章 字符串
可以证明,字符串操作是计算机设计中最常见的行为

13.1 不可变String
String类中每一个看起来会修改String值的方法,实际上都是创建一个全新的String对象。

13.2 重载“+”与StringBuilder
可以用javap命令来反编译class文件,查看代码是如何工作。
例如:类Concatenation
package chapter13;
public class Concatenation {
public static void main(String[] args) {
String mango="mango";
String s="abc"+mango+"def"+47;
System.out.println(s);
}
}

通过javap -c Concatenation后,得到如下字节码:
D:\Program Files\Java\jdk1.6.0_13\bin>javap -c Concatenation
Compiled from "Concatenation.java"
public class chapter13.Concatenation extends java.lang.Object{
public chapter13.Concatenation();
Code:
0: aload_0
1: invokespecial #8; //Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String[]);
Code:
0: ldc #16; //String mango
2: astore_1
3: new #18; //class java/lang/StringBuilder
6: dup
7: ldc #20; //String abc
9: invokespecial #22; //Method java/lang/StringBuilder."<init>":(Ljava/la
ng/String;)V
12: aload_1
13: invokevirtual #25; //Method java/lang/StringBuilder.append:(Ljava/lang
/String;)Ljava/lang/StringBuilder;
16: ldc #29; //String def
18: invokevirtual #25; //Method java/lang/StringBuilder.append:(Ljava/lang
/String;)Ljava/lang/StringBuilder;
21: bipush 47
23: invokevirtual #31; //Method java/lang/StringBuilder.append:(I)Ljava/la
ng/StringBuilder;
26: invokevirtual #34; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;
29: astore_2
30: getstatic #38; //Field java/lang/System.out:Ljava/io/PrintStream;
33: aload_2
34: invokevirtual #44; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
37: return
}
由此可知,编译器创建了一个StringBuilder对象,用于构造最终的String。
注解:dup指令是复制之前分配的java/lang/StringBuilder空间的引用并压入栈顶,invokevirtual指令通过22这个常量池入口需找到了java/lang/ StringBuilder.append()方法,构造方法虽然找到了。但是必须还得知道是谁的构造方法,所以要将之前分配的空间的应用压入栈顶让 invokespecial命令应用才知道原来这个构造方法是刚才创建的那个引用的,调用完成之后将栈顶的值弹出。之后调用astore_1将此时的栈顶值弹出 存入局部变量中去。

13.3 无意识的递归
package chapter13;
import java.util.ArrayList;
import java.util.List;
/*@name InfiniteRecursion.java
* @describe 13.3 无意识的递归
* @since 2013-08-03 00:06
* @author 张彪
*/
public class InfiniteRecursion {
public String toString(){
return "InfiniteRecursion"+ this +"\n"; //this应该改为super.toString()
}
public static void main(String[] args) {
List<InfiniteRecursion> list=new ArrayList<InfiniteRecursion>();
for(int i=0;i<3;i++){
list.add(new InfiniteRecursion());
}
System.out.println(list.toString());
}
}
//报错
/*Exception in thread "main" java.lang.StackOverflowError
at java.lang.StringBuilder.append(StringBuilder.java:119)
at java.lang.StringBuilder.<init>(StringBuilder.java:93)*/

报错原因是由于编译器看到一个String对象之后跟一个“+”号,而后边的对象不是String类型,于是编译器试图将this转换成一个String。正式通过调用this上的 toString()方法,于是发生了递归调用。
如果你这的想打印对象的内存地址,应该用Object.toString()方法。这才是负责此任务的方法。

13.4 String上的操作
String对象的常用方法。
String类的方法都会返回一个新的String对象。同时,如果内容没发生改变,String()方法只是返回指向原对象的引用而已。

13.5 格式化输出
13.5.1 printf()
13.5.2 System.out.format()
J2SE5引入的format()方法。format()方法模仿于C的printf()方法。
package chapter13;
public class SimpleFormat {
public static void main(String[] args) {
int x=5;
float y=4.5f;
System.out.println(x+" "+y);
System.out.printf("%d,%f\n",x,y);
System.out.format("%d,%f",x,y );
}
}

13.5.3 Formatter类
13.5.4 格式化说明符
package chapter13;
import java.util.Formatter;
/*@name Receipt.java
* @describe 13.5.4 格式化说明符
* @since 2013-08-03 01:24
* @author 张彪
*/
//打印一个购物收据
public class Receipt {
private double total=0;
private Formatter f=new Formatter(System.out);
public void printTitle(){
f.format("%-15s %5s %10s\n","Item","Qty","Price");
f.format("%-15s %5s %10s\n","----","----","----");
}
public void print(String name ,int qty, double price){
f.format("%-15.15s %5d %10.2f\n", name,qty,price);
total+=price;
}
public void printTotal(){
f.format("%-15s %5s %10.2f\n","Tax","",total*0.06);
f.format("%-15s %5s %10s\n","","","----" );
f.format("%-15s %5s %10.2f\n","Total","",total*1.06 );
}

public static void main(String[] args) {
Receipt t=new Receipt();
t.printTitle();
t.print("Jack's Magic Bean", 4, 4.25);
t.print("Princess Peas", 3, 5.1);
t.printTotal();
}
}

Formatter提供了对空格与对其的强大功能。

13.5.5 Formatter转换
13.5.6 String.format()

13.6 正则表达式
正则表达式是一种强大而灵活的文本处理工具。
13.6.1 基础
\d 表示一位数字
在 Java中,"\\"的意思是我要插入一个正则表达式的反斜线。
-?\\d+ 表示可能有一个负数,后面有多个数字

13.6.2 创建正则表达式
13.6.3 量词
量词描述一个模式吸收输入文本的方式
贪婪型:
勉强型:用?号来指定,
占有型:

charSequence 接口。

package chapter13;
import java.util.Arrays;

/*@name IntegerMatch.java
* @describe 13.6 正则表达式
* @since 2013-08-03 10:24
* @author 张彪
*/
public class IntegerMatch {
public void match1(){
System.out.println("-123".matches("-?\\d+")); //true
System.out.println("-a3".matches("-?\\d+")); //false
//"+"在正则表达式有特殊的意义,所以这个地方要用转义
System.out.println("+56".matches("(-|\\+)?\\d+")); //true
}
public void splitMethod(){
String knights="Tree in the fores... wih ....a herring!";
String regex1="\\w+";
System.out.println(Arrays.toString(knights.split(" "))); //以" "进行分割
System.out.println(Arrays.toString(knights.split("\\W"))); // "\W"意思是非单词字符 ,"\w"表示一个单词字符
System.out.println(Arrays.toString(knights.split("n\\W+"))); //表示字母n后面跟着一个或多个非单词字符
//split(regex, limit) 重载方法, 第二个参数为限制分割的次数
}
public void replaceMethod(){
System.out.println("abc".replaceFirst("a|b|c","uu")); //uubc
}
//创建正则表达式
public void createRegex(){
for(String patter:new String[]{"Rudolph","[rR]udolph","[rR][aeiou][a-z]ol.*","R.*"}){
System.out.println("Rudolph".matches(patter));
}
}
public static void main(String[] args) {
new IntegerMatch().createRegex();
}
}

13.6.4 Patter和Matcer
Matcher.find()方法可以在CharSequence中查找多个匹配。
package chapter13.string;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Finding {
public void findMethod(){
//模式 "\\w+" 将字符串划分为单词
Matcher m=Pattern.compile("\\w+").matcher("Evening is full of the linet's wings");
while(m.find()){
System.out.print(m.group()+"-");
}
System.out.println();
int i=0;
while(m.find(i)){
System.out.print(m.group()+"-");
i++;
}
}
public static void main(String[] args) {
new Finding().findMethod();
}
}

组(Groups)
组是用括号划分的正则表达式,可以根据组的编号来引用某个组。组号为0表示整个表达式。

start()和end()
Pattern标记
package chapter13.string;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ReFlags {
public static void main(String[] args) {
Pattern p=Pattern.compile("^java", Pattern.CASE_INSENSITIVE|Pattern.MULTILINE);
Matcher m=p.matcher("java has regex\nJava has regex\n" +
"JAVA has regex\n" +
"Regular exression are in Java");
while(m.find()){
System.out.println(m.group()+"-");
}
}
}
/*java-
Java-
JAVA-*/
该例子中的模式将匹配以"java,Java,JAVA"等开头的行。注意group()方法只返回已匹配的部分。

13.6.5 split()方法
split()方法将输入字符串断开成字符串对象数组,断开边界由下列正则表达式确定。
package chapter13.string;
import java.util.Arrays;
import java.util.regex.Pattern;
public class SplitDemo {
public static void main(String[] args) {
String input="This!!unusal use!!of exclamation!!points";
System.out.println(Arrays.toString(Pattern.compile("!!").split(input))); //[This, unusal use, of exclamation, points]
//第二个参数可以限制分割成字符串的数量
System.out.println(Arrays.toString(Pattern.compile("!!").split(input,3))); //[This, unusal use, of exclamation!!points]
}
}

13.6.6 替换操作
replaceFirst(),replaceALl(),appendReplacement()..........
13.6.7 reset()
13.6.8 正则表达式与Java I/O

13.7 扫描输入
Scanner类
Scanner类在 Java SE5中新增的类。
package chapter13.string;
import java.io.BufferedReader;
import java.io.StringReader;
import java.util.Scanner;
public class BetterRead {
public static void main(String[] args) {
Scanner scanner=new Scanner(new BufferedReader(new StringReader("Sir Robin of Camelot\n22 1.61803")));
System.out.println(scanner.nextLine()); //Sir Robin of Camelot
System.out.println(scanner.nextInt()); //22
}
}

13.7.1 Scanner定界符
Scanner默认情况下根据空白字符对输入进行分词。但是你也可以根据正则表达式进行指定自己所需要的定界符
package chapter13.string;
import java.util.Scanner;
public class ScannerDelmiter {
public static void main(String[] args) {
Scanner scanner=new Scanner("12,34,56,78");
scanner.useDelimiter("\\s*,\\s*");
while(scanner.hasNext()){
System.out.println(scanner.nextInt());
}

}
}

13.7.2 用正则表达式扫描

13.8 StringTokenizer
有了正则表达式和Scanner之后,StringTokenizer基本上可以废弃不用了。

13.9 总结

个人总结: 通过这章的学习,对正则表达式有了新的认识。。。。。。。。。。




2013-08-06 0:47 记 @jinrongdajie31.xichengqu.beijing
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值