Java编程思想(十二) —— 字符串(2)

上篇讲到String的基本用法及StringBuilder和String的比较。继续。

给大家感受一下RednaxelaFX的厉害,他大学看的书。

嗯,这就是去硅谷的水平,所以,还是继续看书吧。

1)格式化输出

确实,说到C的printf,是不能用重载的+操作符的。

printf("%d %f", x , y);

%d这些为格式修饰符,%d表示整数,x插入到%d的位置,%f表示浮点数,y查到%f的位置。

Java也模仿了C:

public class TestString {
    public static void main(String[] args) {
        int x = 1;
        float y = 1.223f;
        System.out.printf("%d %f",x,y);
        System.out.println();
        System.out.format("%d %f",x,y);
    }
}

可以用Formatter在控制台完美的控制间隔,不用你自己去数几个空格了。

public class TestString {
    public static void main(String[] args) {
        Formatter fm = new Formatter(System.out);
        fm.format("%-5s %5s %10s ", "Name","Age","School");
    }
}

%数字+s这样的表达像c,位置可以移动。

 System.out.println(String.format("%h", 17));
 fm.format("%h", 17);

16进制的格式化输出。

2)正则表达式(regex :regular expression)

字符串处理,文件批处理中经常使用到,很好用,也是容易忘。这个点结合网上的一些知识点来写。

-? 一个可能带有负号的数字不包括数字。

\d   表示一位数字,注意其他语言的\\是在正则表达式中是一个反斜杠,而在java中是正要插入正则表达式的\。

举一反三,那么\d在java中就是\\d了,真正想插入一条反斜杠就要\\\。

String的匹配 利用String的match方法

public class TestString {
    public static void main(String[] args) {
        System.out.println("-3444".matches("-?\\d+"));
        System.out.println("-3".matches("-?\\d"));
        System.out.println("-3".matches("(-|\\+)?\\d"));
    }
}

result:都是ture

(-|\\+)? 这个比较复杂,|是或的意思,\\+,由于加号有特殊含义,那么要\\转义,所以就是有加号或者负号的其中一个,或者都没有。

split方法:

经常使用的时候是根据空格切割。

String s = Arrays.toString("sdfsdf sf sdf".split(" "));

其实还可以在split参数中输入正则表达式进行切割:

String s = Arrays.toString("sdfsdf sf sdf".split("\\W+"));
String s2 = Arrays.toString("sdfsdf sf sdf".split("n\\W+"));

\w是非单词字符,\w为单词字符,n\\W+ 字母n后跟着一个或多个非中文字符。

参考:

http://blog.csdn.net/kdnuggets/article/details/2526588

和JDK的Pattern类:

Construct Matches
 
Characters
x The character x
\\ The backslash character
\0n The character with octal value 0n (0 <= n <= 7)
\0nn The character with octal value 0nn (0 <= n <= 7)
\0mnn The character with octal value 0mnn (0 <= m <= 3, 0 <= n <= 7)
\xhh The character with hexadecimal value 0xhh
\uhhhh The character with hexadecimal value 0xhhhh
\x{h...h} The character with hexadecimal value 0xh...h (Character.MIN_CODE_POINT  <= 0xh...h <= Character.MAX_CODE_POINT)
\t The tab character (‘\u0009‘)
\n The newline (line feed) character (‘\u000A‘)
\r The carriage-return character (‘\u000D‘)
\f The form-feed character (‘\u000C‘)
\a The alert (bell) character (‘\u0007‘)
\e The escape character (‘\u001B‘)
\cx The control character corresponding to x
 
Character classes
[abc]

a, b, or c (simple class)
[^abc] Any character except a, b, or c (negation)
[a-zA-Z] a through z or A through Z, inclusive (range)
[a-d[m-p]] a through d, or m through p:[a-dm-p] (union)
[a-z&&[def]] d, e, or f (intersection)
[a-z&&[^bc]] a through z, except for b and
c
: [ad-z] (subtraction)
[a-z&&[^m-p]] a through z, and not m through
p
: [a-lq-z](subtraction)
 
Predefined character classes
. Any character (may or may not match line terminators)
\d A digit: [0-9]
\D A non-digit: [^0-9]
\s A whitespace character: [ \t\n\x0B\f\r]
\S A non-whitespace character: [^\s]
\w A word character: [a-zA-Z_0-9]
\W A non-word character: [^\w]
 
POSIX character classes (US-ASCII only)
\p{Lower} A lower-case alphabetic character: [a-z]
\p{Upper} An upper-case alphabetic character:[A-Z]
\p{ASCII} All ASCII:[\x00-\x7F]
\p{Alpha} An alphabetic character:[\p{Lower}\p{Upper}]
\p{Digit} A decimal digit: [0-9]
\p{Alnum} An alphanumeric character:[\p{Alpha}\p{Digit}]
\p{Punct} Punctuation: One of !"#$%&‘()*+,-./:;<=>[email protected][\]^_`{|}~
\p{Graph} A visible character: [\p{Alnum}\p{Punct}]
\p{Print} A printable character: [\p{Graph}\x20]
\p{Blank} A space or a tab: [ \t]
\p{Cntrl} A control character: [\x00-\x1F\x7F]
\p{XDigit} A hexadecimal digit: [0-9a-fA-F]
\p{Space} A whitespace character: [ \t\n\x0B\f\r]
 
java.lang.Character classes (simple java character type)
\p{javaLowerCase} Equivalent to java.lang.Character.isLowerCase()
\p{javaUpperCase} Equivalent to java.lang.Character.isUpperCase()
\p{javaWhitespace} Equivalent to java.lang.Character.isWhitespace()
\p{javaMirrored} Equivalent to java.lang.Character.isMirrored()
 
Classes for Unicode scripts, blocks, categories and binary properties
\p{IsLatin} A Latin script character (script)
\p{InGreek} A character in the Greek block (block)
\p{Lu} An uppercase letter (category)
\p{IsAlphabetic} An alphabetic character (binary property)
\p{Sc} A currency symbol
\P{InGreek} Any character except one in the Greek block (negation)
[\p{L}&&[^\p{Lu}]]  Any letter except an uppercase letter (subtraction)
 
Boundary matchers
^ The beginning of a line
$ The end of a line
\b A word boundary
\B A non-word boundary
\A The beginning of the input
\G The end of the previous match
\Z The end of the input but for the final terminator, if any
\z The end of the input

量词:吸收文本的方式

Greedy quantifiers            贪婪型
X? X, once or not at all
X* X, zero or more times
X+ X, one or more times
X{n} X, exactly n times
X{n,} X, at least n times
X{n,m} X, at least n but not more than m times
 
Reluctant quantifiers
X?? X, once or not at all
X*? X, zero or more times
X+? X, one or more times
X{n}? X, exactly n times
X{n,}? X, at least n times
X{n,m}? X, at least n but not more than m times
 
Possessive quantifiers
X?+ X, once or not at all
X*+ X, zero or more times
X++ X, one or more times
X{n}+ X, exactly n times
X{n,}+ X, at least n times
X{n,m}+ X, at least n but not more than m times
 
Logical operators
XY X followed by Y
X|Y Either X or Y
(X) X, as a capturing group
 
Back references
\n Whatever the nth capturing group matched
\k<name> Whatever the named-capturing group "name" matched
 
Quotation
\ Nothing, but quotes the following character
\Q Nothing, but quotes all characters until \E
\E Nothing, but ends quoting started by \Q
 
Special constructs (named-capturing and non-capturing)
(?<name>X) X, as a named-capturing group
(?:X) X, as a non-capturing group
(?idmsuxU-idmsuxU)  Nothing, but turns match flags i d m s u x U on - off
(?idmsux-idmsux:X)   X, as a non-capturing group with the given flagsidm
s u x on - off
(?=X) X, via zero-width positive lookahead
(?!X) X, via zero-width negative lookahead
(?<=X) X, via zero-width positive lookbehind
(?<!X) X, via zero-width negative lookbehind
(?>X) X, as an independent, non-capturing group

3)Pattern和Matcher

public class TestString {
    public static void main(String[] args) {
        Pattern p = Pattern.compile("\\W+");
        Matcher m = p.matcher("qw");
        System.out.println(m.matches());
    }
}

Pattern.compile,静态方法,Compiles the given regular expression into a pattern。将一个正则表达式编译进Pattern中。

p.mathcer,Creates a matcher that will match the given input against this pattern。创建一个matcher将输入和Pattern匹配。

m.matches,Attempts to match the entire region against the pattern。

boolean,返回匹配结果。

这样就可以传入正则表达式,然后对字符串进行匹配。

1、find和group

public class TestString {
    public static void main(String[] args) {
        String s = "You're kidding me!";
        Pattern p = Pattern.compile("\\w+");
        Matcher m = p.matcher(s);
        while(m.find()){
            System.out.printf(m.group()+" ");
        }

        int i = 0;
        while(m.find(i)){
            System.out.printf(m.group()+" ");
            i++;
        }
    }
}

result: You re kidding me
You ou u re re e kidding kidding idding dding ding ing ng g me me e

find可以遍历字符串,寻找正则表达式的匹配,group是 Returns the input subsequence matched by the previous match。这样返回的便是第一个匹配多个单词字符 ,所以便是You。find传入参数后,可以调整开始搜索的位置,刚开始为0,那么匹配的是You,i+1之后,匹配到的是ou。

2、end和start

while(m.find()){
            System.out.printf(m.group()+" Start:"+m.start()+" End:"+m.end());
}

You Start:0 End:3re Start:4 End:6kidding Start:7 End:14me Start:15 End:17

匹配起始位置的索引,匹配结束位置的索引。

3、split

其实书上讲属性的东西是最简单的,因为文档有,这种文档有的就是自己动手查动手敲代码。Pattern还有两个

String[] split(CharSequence input)

Splits the given input sequence around matches of this pattern.

String[] split(CharSequence input,
int limit)

Splits the given input sequence around matches of this pattern.

String string = "kjj~~lkjl~~lkjlJ~~lkj~~";
System.out.println(Arrays.toString(Pattern.compile("~~").split(string)));
System.out.println(Arrays.toString(Pattern.compile("~~").split(string,2)));

result:
[kjj, lkjl, lkjlJ, lkj]
[kjj, lkjl~~lkjlJ~~lkj~~]

(哈哈,作者竟然在书中直接讽刺Sun里面的java设计者,把Pattern的标记设计得难懂。)

4)替换操作

String replaceAll(String regex,String replacement)

Replaces each substring of this string that matches the given regular expression with the given replacement.

String replaceFirst(String regex,String replacement)

Replaces the first substring of this string that matches the givenregular expression with the given replacement.

replaceFirst替换的是第一个匹配的内容。replaceAll是全部替换。

接下来还有比这两者好用的处理方法,加入你要找出abcd字母并且替换成大写字母,如果用上面两种写法的话就要处理多次。

String string = "asdfb  sdfoiwer  sdfcdf wer sd d sdf  cxvxzcv s ef bob b   b ";
StringBuffer s2 = new StringBuffer();
Pattern pa = Pattern.compile("[abcd]");
Matcher mc = pa.matcher(string);
System.out.println();
while(mc.find()){
    mc.appendReplacement(s2,mc.group().toUpperCase());
}
mc.appendTail(s2);
System.out.println(s2);

result:AsDfB  sDfoiwer  sDfCDf wer sD D sDf  CxvxzCv s ef BoB B   B 

mc.find();
mc.appendReplacement(s2,mc.group().toUpperCase());
mc.appendTail(s2);
System.out.println(s2);

result :Asdfb  sdfoiwer  sdfcdf wer sd d sdf  cxvxzcv s ef bob b   b

替换时也能操作字符串,while的时候能够全部替换,如果不用while,只进行一次find操作,那么s2打印出来的只有A,要达到replaceFirst的效果,要用appendTail方法,加尾巴,就是把剩余没替换的补上。这样才会打印完整。

reset方法:

Matcher mc = pa.matcher(string);

每次mc只能match一个字符串,可以用reset方法重新match其他字符串:

mc.reset(String newString);

5)扫描输入

c的输入很简单,有时java经常写Syso(Eclipse的System.out.println的快捷输入,很早之前一位前辈告诉我的,一直受用)。一直输出,却忘了输入怎么写。

可读流对象:

public class TestScanner {
    public static void main(String[] args) {
        BufferedReader br = new BufferedReader(new StringReader("sdfsdf\nsdfsdf\nsdfsdf"));
        try {
            System.out.println(br.readLine());
            System.out.println(br.readLine());
            System.out.println(br.readLine());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

用Scanner也可以。

Scanner s = new Scanner(System.in);
System.out.println(s.nextLine());

可以在控制台输入后输出。

Scanner定界符:

public class TestScanner {
    public static void main(String[] args) {
        Scanner s = new Scanner("12, 323, 34, 34, 5");
        s.useDelimiter("\\s*,\\s*");
        while (s.hasNextInt()) {
            System.out.println(s.nextInt());
        }
    }
}

昨天看到这里的时候卡住了,本来Scanner根据空白字符对输入进行分词:

Scanner s = new Scanner("12  323 34 34 5");
while (s.hasNextInt()) {
    System.out.println(s.nextInt());
}

这样可以打印每一个数字。

昨天想了好久的就是定界符这个东西,为什么我用\\d+,\\d+不行,今天再来看想通了,其实定界是作为分隔符来看,\\s是空格,而*是零次或多次,这样说就是以逗号前后无空白或者一个或多个空白,将Scanner里面的内容分隔开。

\\d+,\\d+,以逗号前后有数字作为分隔符,肯定不匹配。为了验证,把s改为W一试,也是可以的。

以前没有Scanner和正则表达式的时候,Java使用的是StringTokenizer,现在基本废弃不用了,当然,IDE还没有提示Deprecated.

String内容就到这里了,输入输出,格式化输出,正则表达式,用好的话,在批处理方面甚是强大,有空补充一下String不变性和内存分配的内容。

时间: 2024-10-15 04:34:40

Java编程思想(十二) —— 字符串(2)的相关文章

Java编程思想(十二) —— 字符串(1)

字符串在编程中也是经常使用的. 1)不可变 其实查看API就会发现: public final class String extends Object implements Serializable, Comparable<String>, CharSequence final,不可变的. public class TestString { static String upcase(String s){ return s.toUpperCase(); } public static void

Java编程思想(十八) —— 再谈反射

在Java编程思想(十五) -- 类型信息之反射和Java编程思想(十六) -- 联系JVM再谈Class,书上只用了3页就讲完了,还有讲了那么多Class的东西,接下来要从反射中怎么用,自己结合API和其他资料再写多一些. 示例:Test.java public class Test { public Test() {     }      public Test(int i) {         System.out.println(i);     } private void pri()

【Java编程思想】二、一切都是对象

尽管Java是基于C++的,但是相比之下,Java是一种更“纯粹”的面向对象设计语言. 2.1 用引用操纵对象 一切都被视为对象, 因此可采用单一固定的语法.尽管一切都被看作对象,但操纵的标识符实际上是对象的一个“引用”. Java里的“引用”与C++中的“引用”是有区别的,但是这个概念不需要完全明白,学会处理引用就可以了. 2.2 必须由你创建所有对象 new关键字的意思就是“给我一个新对象”! 2.2.1对象存储到什么地方 1)寄存器 2)堆栈(RAM) 3)堆(RAM) 4)常量存储(RO

Java编程思想(十六) —— 联系JVM再谈Class

编程思想这个专栏停了好久了,主要是把精力放在了其他知识上,现在继续补上. 前面两篇写到RTTI和简单的反射介绍,先回顾一下: RTTI,运行时类型信息,多态的应用,类型转换其实是发生在运行期间. Class对象: 编程思想讲到的定义,Java使用Class对象来执行其RTTI,类是程序的一部分,每个类都有一个Class对象,其实每编写和编译一个新类,就会产生一个Class对象,其实这个对象时被保存在同名的.class文件中的.生成这个类对象,其实是JVM(Java虚拟机)使用了"类加载器&quo

Java编程思想之二十 并发

20.1 并发得多面性 并发编程令人困惑的一个主要原因:使用并发时需要解决的问题有多个,而实现并发的方法也有多种,并且在这两者之间没有明显的映射关系. 20.1.1 更快的执行 速度问题初听起来很简单:如果你需要一个程序运行得更快,那么可以将起断开为多个片段,在单个处理器上运行每个片段. 并发通常是提高运行在单个处理器上的程序的性能,但在单个处理器上运行的并发程序开销确实应该比该程序所有部分都顺序执行开销大,因为其中增加了所谓的上下文切换的代价. 如果没有任务会阻塞,那么在单处理器上使用并发就没

Java编程思想(十五) —— 类型信息之反射

讲完.class,Class之后,继续. 1)泛化的Class引用 Class也可以加入泛型,加入之后会进行类型检查. 贴一下书上原话,Class<?>优于Class,虽然他们是等价的,Class<?>的好处是碰巧或疏忽使用了一个非具体的类引用.我搞不懂这个所谓非具体是什么? 后面弄懂了,其实<?>作为通配符,就是未知的,直接写结论的话不能写个具体类型吧,作者的意思其实就是说加了泛型的Class就是选择了非具体的版本. 加入泛型的原因是提供编译期间的类型检查,操作失误的

《java编程思想》:字符串

1.String对象是不可变的,String类中每个看起来会修改String值的方法,实际上都是创建了一个新的String对象,来包含修改后的内容,所以在对String修改后,想打印新的值,可以直接打印,或者使用变量接受,直接打印原String引用是不会有变化的. 2.通过 "+" 连接String字符串,实际上是编译器自动引入了StringBuilder类,通过append()方法实现的. 3.当为一个类编写toString()方法时,如果字符串操作比较简单,可以直接使用"

Java编程思想笔记(字符串)

1.不可变String:String对象是不变的.String类中每一个看起来会修改String值得方法,实际上都是创建了一个全新的String对象,以包含修改后的字符串内容.而最初的String对象则丝毫未动.(对于一个方法而言,参数是为该方法提供信息的,耳边是想让该方法改变自己的.) 2.重载“+”与StringBuilder

Java编程思想学习(二) 操作符

1. 对象“赋值”:对一个对象进行操作时,我们真正操作的是对对象的引用.所以倘若“将一个对象赋值给另一个对象”,实际是将“引用”从一个地方复制到另一个地方.(引用于对象之间存在关联,但这种关联可以被改变.) 2. == 和 != 比较的是对象的引用. equals() 方法的默认行为是比较引用,如果定义类的对象中对 equals()方法进行重写,则可以实现比较对象的实际内容是否相等的效果. 3. “与” (&&) .“或” (||) .“非” (!) 操作只可应用于布尔值.与在 C 和 C