1.不可变String
1.String对象是不可变的,查看JDK文档你就会发现,String类中每一个看起来修改String值得方法,其实都是创建了一个全新的String对象,以包含修改后的字符串的内容。而最初的String对象则丝毫未动。
2.每当把String对象作为方法的参数时,都会复制一份引用。而该 引用所指的对象其实一直呆在单一的物理位置(内存地址)上,从未动过。
3.其实对于类似于:String s = "landon";String ss = Immutable.upcase(s);难道我们真的希望upcase将参数s改变吗?对于一个方法而言,参数是为该方法提供信息的,而不是想让该方法改变自己的。这一点很重要,正因为有了这保障,才使得代码易于编写和阅读。
2.重载"+"与StringBuilder
1.String对象是不可变的,你可以给一个String对象加任意的别名,因为String对象具有只读特性,所以指向它的任何引用都不可能改变它的值。因此,也就不会对其他引用由什么影响。
2.不可变性会带来一定的效率问题。为String对象重载的"+"操作符就是一个例子。重载的意思是一个操作符在应用于特定的类时,被赋予了特殊的含义。用于String的“+”和“+=”是Java仅有的两个重载过的操作符。而Java程序员不允许程序员重载任何操作符。
注:其实在诸如C#和Python中,它们都有垃圾回收与简单易懂的操作符重载机制。
3.对于了类似String s = "landon" + 23 + ss + "tracy";这样的操作来说,代码可能是这样工作的,String可能有一个append方法,它会生成一个新的String对象,以包连接后的字符串,然后依次类推,依次连接。 这种方式为了生成最后的String,残生了一大堆需要垃圾回收的中间对象,性能相当糟糕。
4.对于上述代码,如何工作。我们可以使用JDK自 带的工具javap来反编译一下字节码。javap -c Class -c将表示生成JVM字节码。通过查看,我们发现:编译器自动引入了StringBuilder.编译器自作主张的使用了它,因为其更高效。在上述例子中,编译器创建了一个StringBuilder对象 ,用以构造最后的String,并为每个字符串调用一次append方法。最后调用toString生成结果。
注:个人推荐使用Bytecode Outline Eclipse插件,更方便。
5.也许你会觉得可以随意使用String对象,反正编译器会为我们优化性能。可以让我们看一下这样的情况,即循环里使用"+",如:
String result = "";
for(int i = 0;i < filels.length;i++)
{
result += fields[i];
}
对于这样情况,我们通过javap反编译,看一下JVM字节码:我们可以发现,StringBuilder对象是在循环内构造的,即每循环一次,都会创建一个新的StringBuilder对象,这样当然效率很低。所以在这样的循环情况下,在循环外显示的创建一个StringBuilder对象,效率会更高。而且如果你已经知道最后的字符串大概有多长的话,可以预先指定StringBuiler的大小,避免多次重新分配缓冲。
6.因此,当你为一个类编写toString方法时,如果字符串操作比较简单的话,你可以信赖编译器,它会你合理的构造最终的字符串结果。不过,你如果要在toString方法中使用循环,那么你最好自己创建一个StringBuilder,用它来构造最终的结果。
7.对于StringBuilder.append,如append(a + ":" + c),编译器就会掉入陷阱,从而为你另外创建一个StringBuilder对象处理括号内的字符串操作。如果拿不准使用哪种方式,随时使用javap来分析你的程序。
8.StringBuilder是JavaSE5引入的,在这之前java用的是StringBuffer,后者是线程安全的,因此开销也会大些,所以在JavaSE5/6中,字符串操作应该还会更快一些。StringBuilder提供了丰富而全面的方法,包括insert,replace,subString,甚至reverse,但是最常用的是append和String.还有delete方法。
3.无意识的递归:
1.Java的每个类从根本上都是继承自Object.标准容器类也不例外。因此容器类都有toString方法,并且覆写了改方法,使得它生成的String结果能够容器自身,以及容器所包含的对象。如ArrayList的toString,它会遍历ArrayList中所包含的对象,调用每个元素上的toString方法。
2.不过对于类似:
public String toString()
{
return "landon" + this + "\n";
}
你也许想调用this打印出对象的内存地址,不过如果运行,则会出现很多异常。原因是在这里发生了自动类型转换,因为编译器看到一个String对象后面跟着一个"+",而再后面的对象不是String的时候 ,它会尝试将this转换成一个String,它如何转换?正是调用this.toString方法,于是就发生了递归调用。
3.如果你真的想要打印出对象的内存地址,应该调用Object的toString方法,这才是负责此任务的方法。所以,你不应该用this,而是super.toString方法。
4.String上的操作:
1.String#intern,为 每一个唯一的字符序列生成一个且仅生成一个String引用。返回字符串对象的规范化表示形式。
一个初始为空的字符串池,它由类 String 私有地维护。 当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(用 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并返回此 String 对象的引用。
它遵循以下规则:对于任意两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。
所有字面值字符串和字符串赋值常量表达式都使用 intern 方法进行操作.返回:一个字符串,内容与此字符串相同,但一定取自具有唯一字符串的池。(常量池)
2.getBytes(),getBytes(Charset charset),getBytes(String charsetName):根据默认字符集或指定的CharSet编码为Byte序列,并将结果存储到一个新的Byte数组。
3.getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin):将字符从此字符串复制到目标字符数组
4.contentEquals(CharSequence cs),contentEquals(StringBuffer sb) :将此字符串与指定的 CharSequence/StringBuffer 比较.
5.regionMatches(int toffset, String other, int ooffset, int len) :测试两个字符串区域是否相等
6.lastIndexOf(),从后向前搜索
7.concat(String str) :将指定字符串连接到此字符串的结尾
注:当需要改变字符串的内容时,String类的方法都会返回一个新的String对象。同时,如果内容没有发生改变,String方法只是返回指向原对象引用而已。这可以节约存储空间以及避免额外的开销。
5.格式化输出:
1.JavaSE5推出了C语言printf风格的格式化输出这一功能。这不仅使得控制输出的代码更加简单,而且也给与Java开发者对于输出格式与排列的更强大的控制能力。
2.C语言printf,占位符-如:printf("Row1: [%d %f] \n",x,y);占位符-格式修饰符,不但说明了插入数据的位置,还说明了插入变量的类型以及如何格式化,这个%d表示x是一个整数,%表示y是一个浮点数(double或者float)
3.System.out.format:
如果你怀旧的话的,也可以使用System.out.printf.JavaSE5引入的format方法可以用于PrintStream和PrintWriter对象。其中也包括System.out对象。format方法模仿C的printf.
4.Formatter类:
在Java中,所有新的格式化功能都由java.util.Formatter类处理。你可以将一个Formatter看做一个翻译器,它将你的格式字符串与数据翻译成所需要的结果。当你创建一个Formatter对象的时候,需要向其构造器传递一些信息,告诉它最终的结果将向那里输出,如new Formatter(System.out);
Formatter的构造器可以经过重载,接受多种输出目的地。不过最常用的还是PrintStream,OutputStream和File
5.格式化说明符:
1.控制空格与对齐:
%[argument_index$][flags][width][.precision]conversion
例:f.format("%-15s %5d %10.2f \n")
width:控制一个域的最小尺寸,指定width实现。Formatter对象通过在必要时添加空格来表示确保一个域至少达到某个长度。默认的情况下,数据是右对齐。不过可以通过改变argument_index,如-,来改变对齐方向。
precision:精度,指明最大尺寸。不是所有的数据类型都可以使用precision.而且应用于不同的数据类型转换时,precision的意义也不同。用于String:表示打印String输出字符的最大数量;应用浮点数:其表示小数部分要显示出来的位数,默认是6位,如果小数位数过多则舍入,太少则在尾部补0.由于整数没有小数部分,所以无法应用precision.如果对整数应用,则会触发异常。
6.Formatter类型转换:
1.d 整数型,10进制,Decimal 2.c unicode字符 3.b boolean值 4.s String 5.f 浮点数(10进制) 6.e 浮点数(科学计数) 7.x 整数 16进制 hex 8.h 散列码(16进制) hash 9.% % 10.o 八进制整数 octal
2.对于boolean类型或者Boolean对象,其转换结果永远是true或者false.但是,对于其他类型的对象,只要改参数不为null,其永远为true.即使是数字0,转换结果依然为true。这在其他语言包括C,往往为false.所以将b应用于非boolean类型的对象时候要格外小心.
7.String.format:
JavaSE5也参考了c的printf方法,以生成格式化的String对象。String.format是一个String对象,其接受与Formatter.format一样的参数 ,但返回一个String对象。当只需要使用format方法一次的时候,String.format用起来很方便。
其实在String.format内部,也是创建了一个StringFormatter对象,然后将传入的参数传递给StringFormatter,不过与其自己做这些事情,还不如使用便捷的String.format方法,何况这样的代码更加清晰易读。
8.16进制转储工具:
1.在处理2进制文件时,我们经常希望以16进制的格式看内容。所以可以做一个工具,利用String.format,以可读的16进制格式将字节数组打印出来。
9.正则表达式
1.很久以前,正则表达式就已经整合到标准Unix的工具集之中,如sed和awk,以及程序设计语言,如python和perl.Java中字符串操作还主要集中在String,StringBuffer,StringTokenizer。正则表达式是一种强大而灵活的文本处理工具。
2.基础
1.一般来说,正则表达式就是以某种方式来描述字符串。
2.-? //可能有一个负号在前面
\d 表示一位数字
\\ Java中表示要插入一个正则表达式的反斜线,所以其后的字符具有特殊的意义。如 \\d ,如果要插入一个普通的反斜线,\\\\,不过换行和制表符之类的东西只需要使用单反斜线\n\t
+ 一个或多个之前的表达式 -?\\d+ //可能有一个负号,后面跟着一位或多位数字
应用正则表达式的最简单途径,就是利用String类内建的功能:String#matches
3.String类还自带了一个非常有用的正则表达式工具,split方法,其功能是"将字符串从正则表达式匹配的地方切开".split还有一个重载的版本,它允许你限制字符串分割的次数。
4.String类自带的最后一个正则表达式工具是替换,你可以只替换正则表达式第一个匹配的字串,或是替换所有匹配的地方。
5.String之外的正则表达式还有更强大的替换工具,如可以通过方法调用执行替换.而且,如果正则表达式不是只使用一次的话,非String对象的正则表达式明显具备更佳的性能。
3.创建正则表达式
1.正则表达式的完整构造子列表,详见Jdk文档java.util.regex包中的Pattern
2.字符类:
[abc] a、b 或 c(简单类)
[^abc] 任何字符,除了 a、b 或 c(否定)
[a-zA-Z] a 到 z 或 A 到 Z,两头的字母包括在内(范围)
[a-d[m-p]] a 到 d 或 m 到 p:[a-dm-p](并集)
[a-z&&[def]] d、e 或 f(交集)
[a-z&&[^bc]] a 到 z,除了 b 和 c:[ad-z](减去)
[a-z&&[^m-p]] a 到 z,而非 m 到 p:[a-lq-z](减去)
预定义字符类
. 任何字符(与行结束符可能匹配也可能不匹配)
\d 数字:[0-9]
\D 非数字: [^0-9]
\s 空白字符:[ \t\n\x0B\f\r]
\S 非空白字符:[^\s]
\w 单词字符:[a-zA-Z_0-o9]
\W 非单词字符:[^\w]
逻辑运算符
XY X 后跟 Y
X|Y X 或 Y
(X) X,作为捕获组
边界匹配器
^ 行的开头
$ 行的结尾
\b 单词边界
\B 非单词边界
\A 输入的开头
\G 上一个匹配的结尾
\Z 输入的结尾,仅用于最后的结束符(如果有的话)
\z 输入的结尾
3.量词
量词描述了一个模式吸收输入文本的方式.
贪婪型:量词总是贪婪的,除非有其他的选项被设置。贪婪表达式会为所有可能的模式发现尽可能多的匹配。导致此问题的一个典型理由就是假定我们的模式仅能匹配第一个可能的字符组,如果它是贪婪的,他们它会继续往下匹配
勉强型:用问号来指定,这个量词匹配满足模式所需的最少字符数。
占有型:目前,这种类型的量词只有在Java语言中才可用。当正则表达式被应用于字符串时,它会产生相当多的状态,一边在匹配失败时可以回溯。而占有的量词并不 保存这些中间状态,因为他们可以防止回溯。他们常常用于防止正则表达式失控,因此可以使正则表达式执行起来更有效。
贪婪型 勉强型 占有型 如何匹配
X? X?? X?+ 一个或0个X
X* X*? X*+ 0个X或多个X
X+ X+? X++ 一个或多个X
X(n) X(n)? X(n)+ 恰好n次X
X(n,) X(n,)? X(n,)+ 至少n次X
X(n,m) X(n,m)? X(n,m)+ X至少n次,且不超过m次
注意,表达式X通常必须要用圆括号括起来,以便他能够按照我们期望的效果去执行。
如abc+,这个表达式表达是:匹配ab,后面跟一个或多个c;如果要表明匹配1个或多个完整的abc字符串,需这样表示(abc)+
4.CharSequence
接口CharSequence从CharBuffer.String.StringBuffer,StringBuilder类之中抽象出了字符序列的一般化定义:
interface CharSequence
{
charAt(int i);
length();
subSequence(int start,int end);
toString();
}
因此这些类都实现了该接口,多数正则表达式操作都接受CharSequence类型的参数。
4.Pattern和Matcher
1.一般来说,比起功能有限的String类,我们更愿意构造功能强大的正则表达式对象。只需要导入java.util.regex包,然后用static Pattern.compile方法来编译你的正则表达式即可.它会根据你的String类型的表达式生成一个Pattern对象。接下来,把你想要检索的字符串传入Pattern对象的matcher方法,matcher方法会生成一个Matcher对象,其有许多功能可以用。如其replaceAll方法能将所有匹配的部分替换成你传入的参数。
Pattern对象表示编译后的正则表达式,我们使用已编译的Pattern对象上的matcher方法,加上一个输入字符串,从而共同构造了一个Matcher对象。同时Pattern类还提供了static方法:
static boolean matches(String regex,charSequence input)
该方法用以检查regex是否匹配整个CharSequence类型的input参数。编译后的Pattern还提供了split方法,它从匹配了regex的地方分割输入字符串,返回分割后的子字符串String数组.
通过调用Pattern.matcher()方法,并传入一个字符串参数,我们得到了一个Matcher对象。通过Matcher上的方法,我们将能够判断各种不同类型的匹配是否成功:
boolean matches();
boolean lookingAt();
boolean find();
boolean find(int start)
其中的matches方法用来判断整个输入字符串是否匹配正则表达式模式.而lookingAt()则用来判断该字符串(不必是整个字符串)的其实部分是否能够匹配模式.
Matcher.find方法可以用来在CharSequence中查找多个匹配.
2.组(Groups)
组是用括号划分的正则表达式,可以根据组的编号引用某个组。组号0表示整个表达式,组号1表示被第一对括号括起的组,一次类推。如
A(B(C))D中有三个组,组0是ABCD,组1是BC,组2是C
Match对象提供了一系列化方法,用于获取与组相关的信息:public int groupCount()返回该匹配器的模式中的分组数目,第0组不包括在内。
public String group()返回前一次匹配操作
public String group(i)返回前一次匹配操作期间指定的组号
public int start(int group)返回在前一次匹配中寻找到的组的起始索引
public int end(int group) 返回在前一次匹配操作中寻找到的组的最后一个字符索引加一的值
3.start()与end()
在匹配操作成功之后,start返回先前匹配的起始位置的索引,而end返回匹配的最后字符的索引值加一的值。匹配操作失败之后或先与一个正在进行的匹配操作去尝试,调用start或end将会产生IllegalStateException.
find()可以在输入的任意位置定位正则表达式,而lookingAt和matches只有在正则表达式与输入的最开始匹配时才会成功->matches只有在整个表达式都匹配正则表达式时才会成功,而lookingAt只要输入的第一部分匹配就会成功。
4.Pattern标记
Pattern类的compile方法还有另外一个版本,就是它接受一个参数,以调整匹配的行为:
Pattern Pattern.compile(String regex,int flag);
flag来自Pattern的常量:
1.Pattern.CANON_EQ->匹配规范的等价性,默认不考虑等价性,如表达式a\u03DA会匹配字符串?
2.Pattern.CASE_INSENSITIVE(?!) ->不考虑大小写
3.Pattern.COMMENTS(?x)->空格符和#开始的注释会被忽略掉(unix的行模式)
4.Pattern.DOTALL(?s)->.匹配所有字符包括行终结符,而默认情况下不匹配行终结符
5.Pattern.MULTILINE(?m)->多行模式下,表达式^和&分别匹配一行的开始和结束。^还匹配输入字符串的开始,而$还匹配输入字符串的结尾。默认情况下,这些表达式仅匹配输入的完整字符串的开始和结束。
6.Pattern.UNICODE_CASE(?u)->当指定这个标记并开启CASE_INSENSITIVE时,大小写不敏感的匹配将按照与Unicode标准相一致的方式进行。默认情况下只按US_ASCII字符集进行
7.Pattern.UNIX_LINES(?d)->在.,^,$行为中,只识别行结束符\n
可以通过|组合多个标记
5.split
split方法将输入字符串断开成字符串对象数组,断开边界有正则表达式确定:
String[] split(CharSequence input)
String[] split(CharSequence input,int limit)
该方法可以按照通用边界断开输入文本,第二种形式的方法可以限制将输入分割成字符串的数量。
6.替换操作
正则表达式特别适合替换文本,其提供了许多方法:replaceFirst(String replacement),以参数字符串替换掉第一个匹配的部分;
repalceAll(String replacement),以参数替换所有匹配成功的部分;
appendReplacement(StringBuffer sbuf,String replacement),执行渐进式的替换,其允许你调用其他方法来生成或处理replacement。
appendTail(StringBuffer sbuf),在执行了一次货多次appendReplacement后,调用此方法可以讲输入字符串余下的部分复制到sbuf中。
7.reset
该方法可以将现有的Matcher对象应用于一个新的字符序列.
10.扫描输入
1.Scanner(#next...,扫描基本类型)
2.默认情况下,Scanner根据空白字符(WHITESPACE_PATTERN)对输入进行分词.->可通过#useDelimiter指定定界符
3.#delimiter()返回当前正在作为定界符使用的Pattern对象.
4.Scanner可结合自定义正则表达式进行扫描复杂数据.
Scanner#hasNext(String pattern)
Scanner#next(String pattern)
Scanner#match()
->仅仅针对下一个输入分词进行匹配.(注意和定界符有区别)
11.StringTokenizer
1Java引入正则表达式和Scanner之前的产物.
2.可废弃不用了.
部分源码:
package com.book.chap13.string;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/** *//**
*
*ArrayList.toString
*<p>遍历ArrayList中所包含的对象,调用每个元素上的toString方法
*
*@author landon
*@version 1.0.0 2012-8-27 下午6:20:50
*@since JDK 1.6.0_30
*
*/
public class ArrayListDisplay
{
public static void main(Stringargs)
{
List<Date> list = new ArrayList<Date>(10);
for(int i = 0;i < 5;i++)
{
list.add(new Date());
}
System.out.println(list);
}
}
package com.book.chap13.string;
/** *//**
*
*String字符串连接
*<p>"+"</p>
*<p>Bytecode Outline
*
*@author landon
*@version 1.0.0 2012-8-27 上午9:31:05
*@since JDK 1.6.0_30
*
*/
public class Concatenation
{
public static void main(Stringargs)
{
String name = "landon";
String s = name + "kobe" + 23 + "tracy";
System.out.println(s);
}
}
package com.book.chap13.string;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** *//**
*
*Matcher.find,用来在CharSequence中查找多个匹配
*
*@author landon
*@since 1.6.0_35
*@version 1.0.0 2012-11-5
*
*/
public class Finding
{
public static void main(String[] args)
{
// \\w+
Matcher matcher = Pattern.compile("\\w+").matcher("The 2002 mvp Tracy Mcgrady");
while(matcher.find())
{
System.out.println(matcher.group() + " ");
}
int i = 0;
//i表示字符串中字符的位置,注意包括空格
//输出:The he e 2002 2002 002 02 2 mvp mvp vp p Tracy Tracy racy acy cy y Mcgrady Mcgrady cgrady grady rady ady dy y
while(matcher.find(i))
{
System.out.print(matcher.group() + " ");
i++;
}
}
}
package com.book.chap13.string;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** *//**
*
*正则表达式(Groups)
*Matcher提供的获取与组相关的信息
*
*@author landon
*@since 1.6.0_35
*@version 1.0.0 2012-11-5
*
*/
public class Groups
{
public static final String POEM =
"I'm tracy mcgrady.\n" +
"You are kobe bryant.\n" +
"Hi,Happy Elements.\n" +
"Hi,Linekong.\n" +
"The Phoenix unity 3D project.\n";
public static void main(Stringargs)
{
//由任意数目的非空格字符(\S+)及随后的任意数目的空格字符(\s+)组成,目的是每行的最后3个单词,每行最后以$结束
//正常情况下,将$与整个输入序列的末端相匹配,我们一定要显示地告知正则表达式注意输入序列中的换行符,这可由序列开头的模式标记(?m)来完成
Matcher matcher = Pattern.compile("(?m)(\\S+)\\s+((\\S+)\\s+(\\S+))$").matcher(POEM);
while(matcher.find())
{
for(int j = 0;j <= matcher.groupCount();j++)
{
System.out.print("[" + matcher.group(j) + "]" + " ");
}
System.out.println();
}
}
}
package com.book.chap13.string;
/** *//**
*
*16进制格式查看工具
*
*@author landon<
*@since 1.6.0_35
*@version 1.0.0 2012-10-23
*
*/
public class Hex
{
public static String format(byte[] data)
{
StringBuilder builder = new StringBuilder();
int n = 0;
for(byte b : data)
{
if(n % 16 == 0)//0,16,32
{
builder.append(String.format("%05x: ", n));//16进制输出n 如输出00000: 00010:
}
builder.append(String.format("%02x ", b));
n++;
if(n % 16 == 0)
{
builder.append("\n");
}
}
return builder.toString();
}
public static void main(Stringargs)
{
//输出结果 00000: 00 10 20 40 7f 一个byte即8位,而类似7f则也为8位,2个宽度即可表示一个byte
//如果是%5x %2x,则输出结果为 0: 0 10 20 40 7f
byte[] data = new byte[]{0,16,32,64,127};
System.out.println(format(data));
}
}
package com.book.chap13.string;
/** *//**
*
*String的不可变性
*
*@author landon<
*@version 1.0.0 2012-8-27 下午5:40:20
*@since JDK 1.6.0_30
*
*/
public class Immutable
{
//参数为字符串String,不会改变参数,而是返回一个新的String
public static String upcase(String s)
{
return s.toUpperCase();
}
public static void main(Stringargs)
{
String q = "landon";
System.out.println(q);
System.out.println(upcase(q));
//q是不可变的
System.out.println(q);
}
}
package com.book.chap13.string;
import java.util.ArrayList;
import java.util.List;
/** *//**
*
*无限递归
*<pre>
* public String toString()
{
return "landon" + this + "\n";
}
*</pre>
*<p>调用this->转为字符串会调用this.toString,导致无限递归
*<p>报错:Exception in thread "main" java.lang.StackOverflowError
*<p>调用super.toString来输出内存地址(Object.toString)
*
*@author landon
*@version 1.0.0 2012-8-27 下午6:27:34
*@since JDK 1.6.0_30
*
*/
public class InfiniteRecursion
{
//@Override
//会报堆栈溢出的错误
/**//*public String toString()
{
return "InfiniteRecursion Address " + this + "\n";
}*/
@Override
public String toString()
{
return "InfiniteRecursion Address " + super.toString() + "\n";
}
public static void main(Stringargs)
{
List<InfiniteRecursion> list = new ArrayList<InfiniteRecursion>();
for(int i = 0;i < 5;i++)
{
list.add(new InfiniteRecursion());
}
System.out.println(list);
}
}
package com.book.chap13.string;
/** *//**
*
*String内建使用正则
*
*<p>-?\\d+ 可能有一个负号(或者没有),后面跟着一位或多位数字
*<p>(-|\\+)?\\d+ |表示或,括号表示分组,该正则表达式表示字符串的起始字符可能是一个+,或者都没有,因为后面跟着?,
*+在正则表达式中有特殊意义,所以必须转义
*
*@author landon
*@since 1.6.0_35
*@version 1.0.0 2012-10-31
*
*/
public class IntegerMatch
{
public static void main(Stringargs)
{
System.out.println("-1234".matches("-?\\d+"));
System.out.println("5678".matches("-?\\d+"));
System.out.println("+111".matches("-?\\d+"));
System.out.println("+911".matches("(-|\\+)?\\d+"));
}
}
package com.book.chap13.string;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** *//**
*
*Pattern的各种标记
*
*@author landon
*@since 1.6.0_35
*@version 1.0.0 2012-11-5
*
*/
public class ReFlags
{
public static void main(Stringargs)
{
Pattern pattern = Pattern.compile("^java",Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
Matcher matcher = pattern.matcher("java has regex\nJava has regex\n" +
"Java has pretty good regular expressions\n" +
"Regular expressions are in Java");
while(matcher.find())
{
//group方法只返回已匹配的部分
System.out.println(matcher.group());
}
}
}
package com.book.chap13.string;
/** *//**
*
*String 正则替换
*
*@author landon
*@since 1.6.0_35
*@version 1.0.0 2012-10-31
*
*/
public class Replacing
{
// "My n..me is Tracy Mcgrady,Welcome to " + "china!";
private static String str = Splitting.tmpSplit;
public static void main(Stringargs)
{
//替换第一个匹配出现T开头,后面跟 一个或多个字母,所以Tracy被替换成了Kobe
System.out.println(str.replaceFirst("T\\w+", "Kobe"));
//表示匹配两个单词的任意一个,| 表示或 Mcgrady|china 不要有空格,即Mcgrady | china,引号内有空格也会有一些问题
System.out.println(str.replaceAll("Mcgrady|china", "beijing"));
}
}
package com.book.chap13.string;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** *//**
*
*Matcher.reset->将现有的Matcher对象应用于一个新的字符序列
*
*@author landon
*@since 1.6.0_35
*@version 1.0.0 2013-11-27
*
*/
public class Resetting
{
public static void main(String[] args) throws Exception
{
Matcher m = Pattern.compile("[frb][aiu][gx]").matcher("fix the rug with bags");
while(m.find())
{
System.out.print(m.group() + " ");
}
System.out.println();
// 调用reset方法
m.reset("fix the rig with rags");
while(m.find())
{
System.out.print(m.group() + " ");
}
}
}
package com.book.chap13.string;
/** *//**
*
*下面每一个正则表达式都能成功匹配字符序列"Rudolph"
*
*@author landon
*@since 1.6.0_35
*@version 1.0.0 2012-11-5
*
*/
public class Rudolph
{
public static void main(Stringargs)
{
for(String pattern : new String[]{"Rudolph","[rR]udolph","[rR][aeiou][a-z]ol.*","R.*"})
{
System.out.println("Rudolph".matches(pattern));
}
}
}
package com.book.chap13.string;
import java.util.Scanner;
/** *//**
*
*使用Scanner#useDelimiter(指定定界符)/#delimiter(返回定界符)方法
*
*@author landon<
*@since 1.6.0_35
*@version 1.0.0 2013-11-27
*
*/
public class ScannerDelimiter
{
public static void main(String[] args)
{
Scanner scanner = new Scanner("1,2,3,4,5");
// 使用逗号(包括逗号前后任意的空白字符)作为定界符
scanner.useDelimiter("\\s*,\\s*");
while(scanner.hasNextInt())
{
System.out.println(scanner.nextInt());
}
}
}
package com.book.chap13.string;
import java.util.Scanner;
import java.util.regex.MatchResult;
/** *//**
*
*Scanner结合正则表达式扫描复杂数据
*
*@author landon
*@since 1.6.0_35
*@version 1.0.0 2013-11-27
*
*/
public class ScannerWithGrep
{
public static void main(String[] args)
{
Scanner scanner = new Scanner("10.130.140.108@27/11/2013 \n" + "10.130.14.119@18/11/2014\n" + "next log section");
// ip@date
String pattern = "(\\d+[.]\\d+[.]\\d+[.]\\d+)@" + "(\\d{2}/\\d{2}/\\d{4})";
while(scanner.hasNext(pattern))
{
scanner.next(pattern);// 找到下一个匹配该模式的输入部分
MatchResult result = scanner.match();// 获得匹配的结果
String ip = result.group(1);
String date = result.group(2);
System.out.format("ip:%s date:%s \n", ip,date);
}
}
}
package com.book.chap13.string;
/** *//**
*
*System.out.format
*<p>System.out.printf
*
*@author landon<
*@version 1.0.0 2012-8-28 下午10:54:27
*@since JDK 1.6.0_30
*
*/
public class SimpleFormat
{
/** *//**
* Row1: [5 4.2342]
Row1: [5 4.234200]
Row1: [5 4.234200]
从输出结果上来看,还是有一定区别的。新的方式会按照占位符,如小数默认6位(精度)
*/
public static void main(String[] args)
{
int x = 5;
double y = 4.2342;
//最原始的方式,System.out.println
System.out.println("Row1: [" + x + " " + y + "]");
//新的方式,format or printf
System.out.format("Row1: [%d %f] \n", x,y);
System.out.printf("Row1: [%d %f] \n", x,y);
}
}
package com.book.chap13.string;
import java.util.Arrays;
import java.util.regex.Pattern;
/** *//**
*
*Pattern.split
*
*@author landon
*@since 1.6.0_35
*@version 1.0.0 2012-11-6
*
*/
public class SplitDemo
{
public static void main(Stringargs)
{
String input = "This!!unusual use!!of exclamation!!points";
System.out.println(Arrays.toString(Pattern.compile("!!").split(input)));
//后者限制了分割成字符串的数量
System.out.println(Arrays.toString(Pattern.compile("!!").split(input,3)));
}
}
package com.book.chap13.string;
import java.util.Arrays;
/** *//**
*
*{@link String#split(String)}
*将字符串从正则表达式匹配的地方切开
*
*@author landon
*@since 1.6.0_35
*@version 1.0.0 2012-10-31
*
*/
public class Splitting
{
public static String tmpSplit = "My n..me is Tracy Mcgrady,Welcome to " + "china!";
//根据某regex切分
public static void spit(String regex)
{
//将切换后的数组转为字符串形式
System.out.println(Arrays.toString(tmpSplit.split(regex)));
}
/**//*
* [My, n..me, is, Tracy, Mcgrady,Welcome, to, china!]
[My, n, me, is, Tracy, Mcgrady, Welcome, to, china]
[My , me is Tracy Mcgrady,Welcome to china!]
*/
public static void main(Stringargs)
{
spit(" ");//普通的字符作为正则表达式,并不包含特殊字符,按空格来划分字符串
spit("\\W+");// \W,意思是为非单词字符,如果W小写,\w,则表示一个单词字符 效果是将标点字符删除
spit("n\\W+");//表示字母n后面跟着一个或多个非单词字符 效果是,与字符串匹配的部分,在最终结果中都不存在了
}
}
package com.book.chap13.string;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** *//**
*
*Matcher的start/end方法
*
*@author landon
*@since 1.6.0_35
*@version 1.0.0 2012-11-5
*
*/
public class StartEnd
{
public static String input =
"my name is tracy landon.\n" +
"I'm from dlnu.\n" +
"I like basketball and programming.\n";
private static class Display
{
private boolean regexPrinted = false;
private String regex;
public Display(String regex)
{
this.regex = regex;
}
void display(String message)
{
if(!regexPrinted)
{
System.out.print(regex);
regexPrinted = true;
}
System.out.println(message);
}
}
static void examine(String s,String regex)
{
Display d = new Display(regex);
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(s);
while(matcher.find())
{
d.display("find() " + matcher.group() + " start = " + matcher.start() + " end = " + matcher.end());
}
if(matcher.lookingAt())
{
d.display("lookingAt() start = " + matcher.start() + " end = " + matcher.end());
}
if(matcher.matches())
{
d.display("matches() start = " + matcher.start() + " end = " + matcher.end());
}
}
public static void main(Stringargs)
{
for(String in : input.split("\n"))
{
System.out.println("input :" + in);
for(String regex : new String[]{"\\w*acy\\w*","\\w*rom","I\\w+","like.*?"})
{
examine(in, regex);
}
}
}
}
package com.book.chap13.string;
/** *//**
*
*String常量池和intern
*
*@author landon<
*@version 1.0.0 2012-8-27 下午9:46:16
*@since JDK 1.6.0_30
*
*/
public class StringPoolAndIntern
{
public static void main(Stringargs)
{
//编译期声明的字符串常量
String s0 = "landon";
String s1 = "landon";
String s2 = "lan" + "don";
//两个输出结果均为true
System.out.println(s0 == s1);
System.out.println(s0 == s2);
System.out.println("~~~~~~~~~");
//new的,非常量
String s3 = "kobe";
String s4 = new String("kobe");
String s5 = new String("kobe");
System.out.println(s3 == s4);
//将kobe加入常量池
s3.intern();
//s5指向了常量池中的kobe引用
s5 = s5.intern();
System.out.println(s3 == s4);////虽然执行了s3.intern(),但它的返回值没有赋给s3
System.out.println(s3 == s4.intern());//说明s4.intern()返回的是常量池中"kobe"的引用
System.out.println(s3 == s5);
}
}
package com.book.chap13.string;
import java.util.Arrays;
import java.util.Scanner;
import java.util.StringTokenizer;
/** *//**
*
*使用StringTokenizer对比Scanner
*
*@author landon
*@since 1.6.0_35
*@version 1.0.0 2013-11-27
*
*/
public class StringTokenizerCompare
{
public static void main(String[] args)
{
String input = "I'm tracy landon!";
// 使用StringTokenizer
StringTokenizer tokenizer = new StringTokenizer(input);
while(tokenizer.hasMoreElements())
{
System.out.print(tokenizer.nextToken() + " ");
}
System.out.println();
// 使用split
System.out.println(Arrays.toString(input.split(" ")));
// 使用Scanner
Scanner scanner = new Scanner(input);
while(scanner.hasNext())
{
System.out.print(scanner.next() + " ");
}
}
}
package com.book.chap13.string;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** *//**
*
*Pattern/Matcher
*1.第一个控制台输入参数是搜索匹配的输入字符串
*2.后面的一个或多个都是正则表达式,其用来在输入的第一个字符串中查找匹配,在Unix、Linux中,命令行中的正则表达式必须用引号括起
*
*@author landon
*@since 1.6.0_35
*@version 1.0.0 2012-11-5
*
*/
public class TestRegularExpression
{
//Args abcabcabcdefabc "abc+" "(abc)+" "(abc)(2,)"
public static void main(String[] args)
{
if(args.length < 2)
{
System.out.println("Usage:\n java TestRegularExpression " + "characterSequence regularExpression");
System.exit(0);
}
//显示""
System.out.println("Input:\"" + args[0] + "\"");
for(String arg : args)
{
System.out.println("Regular expressions: \"" + arg + "\"");
//Pattern
Pattern p = Pattern.compile(arg);
//Match
Matcher m = p.matcher(args[0]);
//Match#matches Match#lookingAt
System.out.println(m.matches() + " " + m.lookingAt() + " ");
while(m.find())
{
System.out.println("Match \"" + m.group()
+ "\" at positions " + m.start() + "-" + (m.end() - 1));
}
}
}
}
package com.book.chap13.string;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** *//**
*
*执行替换
*
*@author landon
*@since 1.6.0_35
*@version 1.0.0 2012-11-6
*
*/
public class TheReplacements
{
public static String input = " /*! I'm tracy landon. Hi,Linekong. !*/";
public static void main(Stringargs)
{
//Pattern.DOTALL下 .会被认为是
Matcher matcher = Pattern.compile("/\\*!(.*)!\\*/",Pattern.DOTALL).matcher(input);
String s;
if(matcher.find())
{
s = matcher.group(1);
//两个空格替换成一个空格,这里使用String.replaceAll->因为只使用了一次,与其编译为pattern,不如直接使用,开销也会小些
s = s.replaceAll(" (2.)", " ");
System.out.println(s);
//替换开头的行的空格
s = s.replaceAll("(?m)^ +", "");
System.out.println(s);
s = s.replaceFirst("[aeiou]", "(VOWELI)");
System.out.println(s);
StringBuffer sbuf = new StringBuffer();
Pattern p = Pattern.compile("[aeiou]");
Matcher matcher2 = p.matcher(s);
while(matcher2.find())
{
//该方法允许你在执行替换的过程中,操作来替换的字符串,这里将找到的元音字母转为大写
matcher2.appendReplacement(sbuf, matcher2.group().toUpperCase());
//appengReplacement还允许你通过$g直接找到匹配的某个组,这里的g就是组号
}
matcher2.appendTail(sbuf);
System.out.println(sbuf);
}
}
}
package com.book.chap13.string;
import java.util.Random;
/** *//**
*
*使用StringBuilder
*
*@author landon
*@version 1.0.0 2012-8-27 上午10:50:50
*@since JDK 1.6.0_30
*
*/
public class UsingStringBuilder
{
public static Random random = new Random(23);
//数组的toString方法
@Override
public String toString()
{
StringBuilder result = new StringBuilder("[");
for(int i = 0;i < 10;i++)
{
result.append(random.nextInt(100));
result.append(",");
}
//删除最后一个逗号,注意数组下标从0开始[start,end-1]
result.delete(result.length() - 2, result.length());
result.append("]");
return result.toString();
}
public static void main(Stringargs)
{
UsingStringBuilder usb = new UsingStringBuilder();
System.out.println(usb);
}
}
package com.book.chap13.string;
/** *//**
*
*显示的使用StringBuiler与编译器优化的StringBuilder
*
*@author landon
*@version 1.0.0 2012-8-27 上午9:49:58
*@since JDK 1.6.0_30
*
*/
public class WhitherStringBuilder
{
/** *//**
*
* 未使用StringBuilder(隐式),编译器会自动引入,不过是每次循环都会创建一个StringBuilder对象
*
* @param fields
* @return
*/
public String implict(String[] fields)
{
String result = "";
for(int i = 0;i < fields.length;i++)
{
result += fields[i];
}
return result;
}
/** *//**
*
* 显示的在循环外只创建了一个StringBuilder
*
* @param fields
* @return
*/
public String explicit(String[] fields)
{
StringBuilder result = new StringBuilder();
for(int i = 0;i < fields.length;i++)
{
result.append(fields[i]);
}
return result.toString();
}
}
posted on 2013-11-27 18:03
landon 阅读(2066)
评论(1) 编辑 收藏 所属分类:
Book