《JAVA编程思想》学习笔记---第十三章:字符串

1,不可变String

String对象时不可变的,每一个看起来会修改String的方法,实际上都是创建了一个全新的String对象,而最初的String对象丝毫未动!

package com.str;

public class Immutable {

    public static String upcase(String s){
        return s.toUpperCase();
    }

    public static void main(String[] args) {
        String q = "howpy";
        System.out.println(q);
        String qq = upcase(q);
        System.out.println(qq);
        System.out.println(q);
    }

}

重载“+”与StringBuilder

“+”可用于String:

package com.str;

public class Concatenation {

    public static void main(String[] args) {
        String mango = "mango";
        String s = "abc"+mango+"def"+47;
        System.out.println(s);
    }

}

这种进行字符串的拼接,其实在底层编译器会把String替换成StringBuilder来提高效率。
这种一次性的操作字符串可以使用String,编译器会帮助我们替换,不过在循环中操作字符串可以手动替换为StringBuilder来提高效率!
StringBuilder有佷多丰富而全面的方法!

package com.str;

import java.util.*;

public class UsingStringBuilder {

    public static Random rand = new Random(47);
    public String toString(){
        StringBuilder result = new StringBuilder("[");
        for(int i = 0; i < 25;i++){
            result.append(rand.nextInt(100));
            result.append(",");
        }
        result.delete(result.length()-1,result.length());
        result.append("]");
        return result.toString();
    }
    public static void main(String[] args) {
        UsingStringBuilder usb = new UsingStringBuilder();
        System.out.println(usb);
    }

}

3,无意识的递归

java每个类都集成Object,因此容器类都有toString()方法,并且重写了该方法,这使得他生成的String结果能够表达容器自身。
当使用ArrayList.toString()方法时,它会遍历ArrayList中包含的所有变量,并且调用每个元素的toString()方法!

package com.str;

import java.util.*;

public class ArrayListDisplay {

    public String toString(){
        return "toString";
    }

    public static void main(String[] args) {
        List<ArrayListDisplay> a = new ArrayList<>();
        for(int i  = 0; i< 10; i++){
            a.add(new ArrayListDisplay());
        }
        System.out.println(a);
    }

}

当希望toString()方法打印对象的内存地址,也许你会烤炉使用this关键字,像下面这样:

        return "toString"+this;
    }

运行时,会报一大堆错。因为使用+号时,编译器会将ArrayListDisplay强制转换为String。
正确的方式是调用Object.toString()方法!

public String toString(){
        return "toString"+super.toString();
    }

4,String上的操作

一系列的方法

5,格式化输出

5.1,printf()

java有和c语言一样的格式化输出语句printf(),

package com.str;

public class Printf {

    public static void main(String[] args) {
        int i = 1;
        System.out.printf("i=%d",i);
    }

}

5.2,System.out.format()

format与printf()一样

5.3,Formatter类

Formatter需要向其构造器传递一些信息,以告诉它最终的结果将传向哪里

package com.str;

import java.io.*;
import java.util.*;

public class Turtle {

    private String name;
    private Formatter f;

    public Turtle(String name,Formatter f){
        this.name = name;
        this.f = f;
    }

    public void move(int x, int y){
        f.format("%s id(%d,%d)\n", name,x,y);
    }

    public static void main(String[] args) {
        PrintStream out = System.out;
        Turtle tommy = new Turtle("tommy",new Formatter(System.out));
        Turtle terry = new Turtle("terry",new Formatter(out));
        tommy.move(0, 0);
        terry.move(4, 8);
        tommy.move(3, 4);
        terry.move(2, 5);
        tommy.move(3, 3);
        terry.move(3, 3);
    }

}

格式化说明符

package com.str;

import java.util.Formatter;

public class Receipt {

    private double total = 10;
    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",4,4.25);
        f.format("%-15s %5s %10s\n", "","","-----");
        f.format("%-15s %5s %10.2f\n", "Total","",total);
    }

    public static void main(String[] args) {
        Receipt receipt = new Receipt();
        receipt.printTitle();
        receipt.print("abc", 1, 4.25);
        receipt.print("def", 2, 4.25);
        receipt.print("ghi", 3, 4.25);
        receipt.printTotal();
    }

}
/*
输出:
Item              Qty      Price
----              ---      -----
abc                 1       4.25
def                 2       4.25
ghi                 3       4.25
Tax                 4       4.25
                           -----
Total                      22.75
*/

数字代表所占位数,-号代表左对齐

Formatter转换

最常用的类型转换:
d:整数型(十进制)
c:Unicode字符
b:Boolean值
s:String
f:浮点数(十进制)
e:浮点数(科学计数)
x:整数(十六进制)
h:散列码
%: 字符“%”

String.format()

在String.format()内部,也是创建一个Formatter对象,然后调用format()。

6,正则表达式

关于正则表达式,不进行介绍了。
看java中是如何实现正则表达式的。
java正则表达式中的“\”与其他语言中的不一样!

public class IntegerMatch {

    public static void main(String[] args) {
        System.out.println("-1234".matches("-?\\d+"));
        System.out.println("5678".matches("-?\\d+"));
        System.out.println("+911".matches("-?\\d+"));
        System.out.println("+911".matches("(-|\\+)?\\d+"));
    }

}
/*
输出:
true
true
false
true
*/

java中的“\”与其他语言的“\”是一样的。
字符串类型有matches()方法,返回布尔值,参数是一个正则表达式。

String类还有一个正则表达式工具——spliy(),用于将字符串从正则表达式的地方切开。

package com.str;

import java.util.Arrays;

public class Splitting {

    public static String knights = "Then-when you have found the";

    public static void split(String regex){
        System.out.println(Arrays.toString(knights.split(regex)));
    }

    public static void main(String[] args) {
        split(" ");
        split("\\w+");
        split("n\\w+");
    }

}
/*
输出:
[Then-when, you, have, found, the]
[, -,  ,  ,  ,  ]
[Then-when you have fou,  the]
*/

\w代表单词字符。

另一个有用的工具是替换工具。

package com.str;

public class Replacing {

    public static void main(String[] args) {
        String knights = "Then-when you have found the found";
        System.out.println(knights.replaceFirst("f\\w+", "located"));
        System.out.println(knights.replaceAll("f\\w+", "located"));
    }

}
/*
输出:
Then-when you have located the found
Then-when you have located the located
*/

创建正则表达式

正则表达式的完整构造子列表,参考JDK文档java.util.regex的Pattern类.

字符

B          指定字符B
\xhh       十六进制值为oxhh的字符
\xhhhh     十六进制表示为oxhhhh的Unicode字符
\t         制表符tab
\n         换行符
\r         回车
\f         换页
\e         转义(Escape)

字符类

[abc]         包含a,b,和c,的任何字符(和a|b|c作用相同)
[^abc]        除了a,b,c,之外的任何字符
[a-zA-Z]      从a到z或从A到Z的任何字符(范围)
[abc[hij]]    任意a,b,c,h,i,j字符,与a|b|c|h|i|j作用相同
[a-z&&[hij]]  任意h,i,或j(取交集)
\s            空白符(空格,tab,换行,换页,和回车)
\S            非空白符([^0-9])
\d            数字[0-9]
\D            非数字[^0-9]
\w            词字符[a-zA-Z0-9]
\W            非词字符[^\w]

逻辑操作符

XY          Y跟在X后面
X|Y         X或Y
(X)         捕获组(capturing group)。可以在表达式中用\i引用第i个捕获组

边界通配符

^            一行的开始
$            一行的结束
\b           词的边界
\B           非词的边界
\G           前一个匹配结束

如下代码示例:

package com.str;

public class Rudolph {

    public static void main(String[] args) {
        for(String pattern : new String[]{"Rudolph","[rR]udolph","[rR][aeiou][a-z]ol.*","R.*"}){
            System.out.println("Rudolph".matches(pattern));
        }
    }

}
/*
输出:
true
true
true
true
*/

量词

  • 贪婪性
  • 勉强性
  • 占有性(java特有的)
    书上没给示例,不太懂,标记一下

Pattern和matcher

package com.str;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TestRegularExpression {

    public static void main(String[] args) {
        Pattern p = Pattern.compile("a(\\w)+");
        Matcher m = p.matcher("aaa abc aqu iop");
        while(m.find()){
            System.out.println(m.group()+" "+m.start()+" "+m.end());
        }
        System.out.println(Pattern.matches("a+", "aaa"));
        String[] s = p.split("aaa,abc.adf");
        for(String ss:s){
            System.out.print(ss+" ");
        }
    }

}
/*
输出:
aaa 0 3
abc 4 7
aqu 8 11
true
 , . 
*/

Pattern.compile();方法生成一个正则表达式对象,然后用此对象的matcher()方法匹配想要匹配的字符串,该方法返回一个Matcher对象。

Matcher对象有佷多方法。
find()方法返回布尔值,这个方法会从头到尾一直匹配,只要匹配到就返回ture,重载的find()还能有一个整数的参数,规定匹配开始的位置,不过后一个find()方法会不断的回到搜索的其实位置,而不会往下匹配!
group()方法返回匹配到的字符串
start()与end()方法返回所匹配的子串在父串的位置。

另外,Pattern的静态方法matches()接受一个正则表达式,和一个字符串,返回布尔值,以此来判断是否完全匹配。
Pattern对象有split()方法,它接受一个字符串,然后把这个字符串根据compile()的正则表达式分割成一个字符串数组。

7,扫描输入

如果不用扫描输入,那么从文件和标准输入则很麻烦,看如下代码:

package com.str;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;

public class SimpleRead {

    public static BufferedReader input  = new BufferedReader(
            new StringReader("Sir Robin of Camelot\n22 1.61803"));
    public static void main(String[] args) throws IOException {
        System.out.println("what is your name?");
        String name = input.readLine();
        System.out.println(name);
        System.out.println("double");
        System.out.println("(double)");
        String numbers = input.readLine();
        System.out.println(numbers);
        String[] numArray = numbers.split(" ");
        int age = Integer.parseInt(numArray[0]);
        double favorite = Double.parseDouble(numArray[1]);
        System.out.println(age);
        System.out.println(favorite);
    }

}
/*
输出:
what is your name?
Sir Robin of Camelot
double
(double)
22 1.61803
22
1.61803
*/

可以看到,需要一行一行的读取,然后进行截取,再用Integer,Double的各种解析方法来解析数据。

使用扫描类Scanner则很方便:

package com.str;

import java.util.Scanner;

public class BetterRead {

    public static void main(String[] args) {
        Scanner stdin = new Scanner(SimpleRead.input);
        System.out.println("name");
        String name = stdin.nextLine();
        System.out.println(name);
        System.out.println("double");
        int age = stdin.nextInt();
        double favorite = stdin.nextDouble();
        System.out.println(age);
        System.out.println(favorite);
    }

}

Scanner的构造器可以接受很合类型的输入对象,包括FILE对象,InputStream,String和Readable。

Scanner界定符

在默认情况下,Scanner根据空白字符对输入进行分词,但也可以使用正则表达式指定自己的界定符;

package com.str;

import java.util.Scanner;
import java.util.regex.Pattern;

public class ScannerDelimiter {

    public static void main(String[] args) {
        Scanner scanner = new Scanner("12,42,78,99,42");
        scanner.useDelimiter("\\s*,\\s*");
        Pattern p = scanner.delimiter();
        while(scanner.hasNextInt()){
            System.out.println(scanner.nextInt());
        }
    }

}

useDelimiter()方法规定要使用的界定符,delimiter()返回界定符正则表达式的Pattern对象。

用正则表达式扫描

扫描复杂数据:

package com.str;

import java.util.Scanner;
import java.util.regex.MatchResult;

public class ThreatAnalyzer {

    static String threatDate = 
            "59.27.82.161@02/10/2016\n"+
            "59.27.82.161@01/10/2016\n"+
            "[abc deg asd asd qwe]";

    public static void main(String[] args) {
        Scanner sc = new Scanner(threatDate);
        String pattern = "(\\d+[.]\\d+[.]\\d+[.]\\d+)@"+
                "(\\d{2}/\\d{2}/\\d{4})";
        while(sc.hasNext(pattern)){
            sc.next(pattern);
            MatchResult match = sc.match();
            String ip = match.group(1);
            String date = match.group(2);
            System.out.println("Thread on "+date+" from "+ip);
        }
    }

}
/*
输出:
Thread on 02/10/2016 from 59.27.82.161
Thread on 01/10/2016 from 59.27.82.161
*/

先分析数据的格式,写出相应的正则表达式,在使用Scanner对象的next()方法时,把正则表达式当做参数传入,然后调用match()方法就会返回一个MatchResult对象,用该对象操作数据。
在此需要注意的是正则表达式中不要有界定符!

8,StringTokenizer

使用正则表达式和Scanner分隔字符串就可以了,这个类已经废弃不用了!,不用管了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值