Thinking in java 第13章 字符串 筆記+習題

Thinking in java 第13章 字符串

學習目錄


13.1 不可變String

 

13.2 重載“+”與StringBuilder

1. 用於String的“+”與“+=”是Java中僅有的兩個重載過的操作符,而Java不允許程序員重載任何操作符。而String的不變性會爲此帶來效率問題。

2. 在使用字符串相加的時候,編譯器自動引入StringBuilder。

3. 顯示地創造StringBuilder允許你預先爲其指定大小,可以避免多次重新分配緩衝。在循環中這比編譯器對String的優化要高效,String在每次循環都要新建一個StringBuilder,而顯示只新建一次。

4. StringBuilder提供的方法:insert()、replace()、substring()、reverse()、append()、toString()

 

13.3 無意識的遞歸

1. toString()如果要返回地址,不能直接用this,因爲編譯器會自動調用this.toString()引起無限循環而報錯。應該用super.toString()。

 

13.4 String上的操作

 

13.5 格式化輸出

1. 如下:

System.out.format("Row 1: [%d %f]", x, y);

2. 類中自定義格式化輸出:

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

public class temp {
    public static void main(String[] args) {
        PrintStream outAlias = System.out;
        tempTurtle tommy = new tempTurtle("tommy", new Formatter(System.out));
        tempTurtle terry = new tempTurtle("terry", new Formatter(outAlias));
        tommy.move(1,1);
        terry.move(2,2);
    }
}

class tempTurtle {
    private  String name;
    private Formatter f;

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

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

/*
tommy The Turtle is at (1,1)
terry The Turtle is at (2,2)
*/

3. 格式化說明符

%[argument_index$][flags][width][.precision]conversion

width用於控制域的尺寸,不夠的用空格填補,flag用"-"時表示右對齊,默認爲左對齊;precision用於String時表示最大長度,用於浮點數表示最大位數(默認6位),過多則舍入,過少則補零,不能用於整數,會報錯。

f.format("%-15.15s %5s %10.2f\n". )

4. 

類型轉換字符
d 整數型
c Unicode字符
b Boolean
s String
f 浮點數
e 浮點數(科學計數)
x 整數(十六進制)
h 散列碼(十六進制)
% “%”

5. 輸出可以轉換爲boolean,但是隻要不是null就都是true。

6. String.format()用法一樣,可用於構造字符串。

 

13.6 正則表達式

1. 在其他語言中,"\\"表示插入一個普通的反斜線;在Java中"\\"表示插入一個正則表達式的反斜線。因此Java中一個普通片那個的反斜線表示爲"\\\\"。不過換行和製表符之類的單反斜線即可。

2. 在split()、replaceFirst()、replaceAll()等中可以用正則,將字符串從正則表達式匹配的地方切開。如 .split("\\W+") 切開非字符處。

3. 具體格式可在JDK文檔中java.util.regex.Pattern查詢。

4. Pattern和Matcher的用法:

Pattern p = Pattern.compile(regex);
Marcher m = p.matcher(string);
while(m.find()) {
    print("Match \"" + m.group() + "\" at positions " + m.start() + "-" + (m.end()-1))
}

Pattern的matches(String regex, CharSequence input)方法檢查是否匹配;編譯後的Pattern對象還提供split()返回分割後的String數組。

5. 組(Group)。如A(B(C))D中0組爲ABCD,1組爲BC,2組爲C。用Matcher的groupCount()返回組數,group(int i)返回每組的匹配。

6. Pattern表記,用法:

Pattern Pattern.compile(String regex, int flag)

比較有用的有:Pattern.CASE_INSESITIVE、Pattern.MUTILINE、Pattern.COMMENTS。

7. appendReplace(StringBuffer sbuf, String replacement)可以一邊找一邊換,循序漸進,做類似指定替換幾次的事。最後用m.appendTail(StringBuffer sbuf)將剩餘部分添加進去即可。

 

13.7 掃描讀入

1. 逐行讀入:

BufferReader input = new BufferReader( new StringReader("aaaa"));
String s = input.readLine();

讀入String後用split切分,再用Integer或Double中地方法進行轉換。

2. Java SE5後新增了Scanner類,用nextLine()讀取。

3. Scanner不用加try區塊抓IOException,會自動吞掉。可以用ioException()方法找到最近發生的異常。

4. Scanner定界符,useDelimiter(String regex)

Scanner sc = new Scanner("1, 2, 3, 4");
sc.useDelimiter("\\s*,\\s*");
while(sc.hasNextInt()) print(sc.nextInt());

5. 用正則表達式掃描

Scanner sc = new Scanner(s);
String pattern = ...;
while(sc.hasNext(pattern)) {
    sc.next(pattern);
    MatchResult match = sc.match();
    print(match.group(0)+...);
}

它僅僅針對下一個輸入分詞進行匹配,如果你的正則表達式中含有定界符,那永遠都不可能匹配成功。

 


習題:

練習1:分析reusing/SprinklerSystem.java的SprinklerSystem.tString()方法,看看明確地使用StringBuilder是否確實能夠避免產生過多的StringBuilder對象。

能。使用StringBuilder後只新建了一個對象。【注:StringBuilder與StringBuffer基本沒區別,不過前者是線程不安全的,後者是線程安全的(通過上鎖)】

練習2:修復InfiniteRecursion.java

打印地址要將this改爲super.toString()

練習3:修改Turtle.java,使之將結果輸出到System,err中。

package Chapter13;

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

public class E3 {
    public static void main(String[] args) {
        PrintStream outAlias = System.err;
        E3Turtle tommy = new E3Turtle("tommy", new Formatter(System.err));
        E3Turtle terry = new E3Turtle("terry", new Formatter(outAlias));
        tommy.move(1,1);
        terry.move(2,2);
    }
}

class E3Turtle {
    private  String name;
    private Formatter f;

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

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

/*
tommy The Turtle is at (1,1)
terry The Turtle is at (2,2)
*/

練習4:修改Receipt.java,令所有的寬度都由一個常量來控制。目的是使寬度的變更更容易,只需修改一處即可。

略。開幾個變量,regex在format外部生成即可。

練習5:針對前邊表格中的各種基本轉化類型,請利用所有可能的格式修飾符,寫出一個儘可能複雜的格式化表達式。

"%-1.3f %2d %10.5s"

練習6:創建一個包含int、long、float、double元素的類。應用String.format()方法爲這個類編寫toString()方法,並證明能正常工作。

package Chapter13;

public class E6 {
    public static void main(String[] args) {
        E6A e = new E6A(1,2,3,4);
        System.out.println(e);
    }
}

class E6A {
    private final String regex = "int: %-5d, float: %-5.2f, long: %-5d, double: %-5.2f";
    private int a;
    private float b;
    private long c;
    private double d;

    public E6A(int a, float b, long c, double d) {
        this.a = a;
        this.b = b;
        this.c = c;
        this.d = d;
    }

    public String toString() {
        return String.format(regex, a, b, c, d);
    }
}

/*
int: 1    , float: 2.00 , long: 3    , double: 4.00 
*/

練習7:請參考java.util.regex.Pattern的文檔,編寫一個正則表達式,檢查一個句子是否以大寫字母開頭,以句號結尾。

package Chapter13;

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

public class E7 {
    public static void main(String[] args) {
        String regex = "^[A-Z].*[\\.]$";
        String text = "This is a nice day.";
        String text2 = "this is a nice day.";
        Pattern p = Pattern.compile(regex);
        Matcher m1 = p.matcher(text);
        System.out.println(m1.matches());
        Matcher m2 = p.matcher(text2);
        System.out.println(m2.matches());
    }
}

/*
true
false
*/

練習8:將字符串Splitting.knights在the和you處分割。

package Chapter13;

import java.util.Arrays;

public class E8 {
    public static String knights =
            "Then, when you have found the shrubbery, you must " +
                    "cut down the mightiest tree in the forest... " +
                    "with... a herring!";

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

    public static void main(String[] args) {
        split("the|you");
    }
}

/*
[Then, when ,  have found ,  shrubbery, ,  must cut down ,  mightiest tree in ,  forest... with... a herring!]
*/

練習9:參考java.util.regex.Pattern的文檔,用下劃線替換Splitting.knights中的所有元音字母。

package Chapter13;

public class E9 {
    public static String knights =
            "Then, when you have found the shrubbery, you must " +
                    "cut down the mightiest tree in the forest... " +
                    "with... a herring!";

    public static void replace(String regex) {
        System.out.println(knights.replaceAll(regex, "_"));
    }

    public static void main(String[] args) {
        replace("[aeiou]");
    }
}

/*
Th_n, wh_n y__ h_v_ f__nd th_ shr_bb_ry, y__ m_st c_t d_wn th_ m_ght__st tr__ _n th_ f_r_st... w_th... _ h_rr_ng!
*/

練習10:對字符串Java now has regular expressions驗證下列正則表達式是否鞥夠發現一個匹配。

package Chapter13;

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

public class E10 {
    public static String text = "Java now has regular expressions";

    public static void match(String regex) {
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(text);
        System.out.println("regex : " + regex);
        while(m.find()) {
            System.out.println("Match \"" + m.group() + "\" at position " +
                    m.start() + ((m.end() - m.start() < 2) ? "" :  ("-" + (m.end() - 1))));
        }
    }

    public static void main(String[] args) {
        match("^Java");
        match("\\Berg.*");
        match("n.w\\s+h(a|i)s");
        match("S?");
        match("S+");
        match("s{4}");
        match("s{1}.");
        match("s{0,3}");
    }
}

/*
regex : ^Java
Match "Java" at position 0-3
regex : \Berg.*
regex : n.w\s+h(a|i)s
Match "now has" at position 5-11
regex : S?
Match "" at position 0
Match "" at position 1
Match "" at position 2
Match "" at position 3
Match "" at position 4
Match "" at position 5
Match "" at position 6
Match "" at position 7
Match "" at position 8
Match "" at position 9
Match "" at position 10
Match "" at position 11
Match "" at position 12
Match "" at position 13
Match "" at position 14
Match "" at position 15
Match "" at position 16
Match "" at position 17
Match "" at position 18
Match "" at position 19
Match "" at position 20
Match "" at position 21
Match "" at position 22
Match "" at position 23
Match "" at position 24
Match "" at position 25
Match "" at position 26
Match "" at position 27
Match "" at position 28
Match "" at position 29
Match "" at position 30
Match "" at position 31
Match "" at position 32
regex : S+
regex : s{4}
regex : s{1}.
Match "s " at position 11-12
Match "ss" at position 26-27
regex : s{0,3}
Match "" at position 0
Match "" at position 1
Match "" at position 2
Match "" at position 3
Match "" at position 4
Match "" at position 5
Match "" at position 6
Match "" at position 7
Match "" at position 8
Match "" at position 9
Match "" at position 10
Match "s" at position 11
Match "" at position 12
Match "" at position 13
Match "" at position 14
Match "" at position 15
Match "" at position 16
Match "" at position 17
Match "" at position 18
Match "" at position 19
Match "" at position 20
Match "" at position 21
Match "" at position 22
Match "" at position 23
Match "" at position 24
Match "" at position 25
Match "ss" at position 26-27
Match "" at position 28
Match "" at position 29
Match "" at position 30
Match "s" at position 31
Match "" at position 32
*/

練習11:使用正則表達式 (?i)((^[aeiou])|(\s+[aeiou]))\w+?[aeiou]\b 匹配字符串 "Arline ate eight apples and one orange while Anita hadn't any"

package Chapter13;

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

public class E11 {
    public static String text = "Arline ate eight apples and one orange while Anita hadn't any";

    public static void match(String regex) {
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(text);
        System.out.println("regex : " + regex);
        while(m.find()) {
            System.out.println("Match \"" + m.group() + "\" at position " +
                    m.start() + ((m.end() - m.start() < 2) ? "" :  ("-" + (m.end() - 1))));
        }
    }

    public static void main(String[] args) {
        match("(?i)((^[aeiou])|(\\s+[aeiou]))\\w+?[aeiou]\\b");
    }
}

/*
regex : (?i)((^[aeiou])|(\s+[aeiou]))\w+?[aeiou]\b
Match "Arline" at position 0-5
Match " ate" at position 6-9
Match " one" at position 27-30
Match " orange" at position 31-37
Match " Anita" at position 44-49
*/

練習12:修改Groups.java類,找出所有不以大寫字母開頭的詞,不重複地計算其個數。

package Chapter13;

import java.util.*;
import java.util.regex.*;

public class E12 {
    static public final String POEM =
            "Twas brillig, and the slithy toves\n" +
                    "Did gyre and gimble in the wabe.\n" +
                    "All mimsy were the borogoves,\n" +
                    "And the mome raths outgrabe.\n\n" +
                    "Beware the Jabberwock, my son,\n" +
                    "The jaws that bite, the claws that catch,\n" +
                    "Beware the Jubjub bird, and shun\n" +
                    "The frumious Bandersnatch.";
    public static void main(String[] args) {
        Matcher m = Pattern.compile("(^[a-z]|\\s+[a-z])\\w+").matcher(POEM);
        Set<String> words = new TreeSet<String>();
        while(m.find()) {
            words.add(m.group());
        }
        System.out.println("Number of unique non-cap words = " + words.size());
        System.out.println(words);
    }
}

/*
Number of unique non-cap words = 25
[ and,  bird,  bite,  borogoves,  brillig,  catch,  claws,  frumious,  gimble,  gyre,  in,  jaws,  mimsy,  mome,  my,  outgrabe,  raths,  shun,  slithy,  son,  that,  the,  toves,  wabe,  were]
*/

練習13:修改StartEnd.java,讓它使用Group.POEM爲輸入,必要時修改正則表達式,使find()、lookingAt()和matches()都有機會匹配成功。

略。

練習14:用String.split()重寫SplitDemo。

string.split(String regex);

練習15:修改JGrep.java類,令其能夠接受模式標誌參數。

在regex前加上(?i)、(?m)等即可。

練習16-練習19 略。

練習20:編寫一個包含int、long、float、double和String屬性的類。爲它編寫一個構造器,接收一個String參數。然後掃描該字符串,爲各個屬性賦值。再添加一個toString()方法,用來演示你的類是否工作正確。

package Chapter13;

import java.util.Scanner;

public class E20 {
    public static void main(String[] args) {
        E20A e = new E20A("aaaa 1 2 3 4");
        System.out.println(e);
    }
}

class E20A {
    private final String regex = "String: %s, int: %-5d, float: %-5.2f, long: %-5d, double: %-5.2f";
    private String s;
    private int a;
    private float b;
    private long c;
    private double d;

    public E20A(String s) {
        Scanner sc = new Scanner(s);
        this.s = sc.next();
        this.a = sc.nextInt();
        this.b = sc.nextFloat();
        this.c = sc.nextLong();
        this.d = sc.nextDouble();
    }

    public String toString() {
        return String.format(regex, s, a, b, c, d);
    }
}

/*
String: aaaa, int: 1    , float: 2.00 , long: 3    , double: 4.00 
*/

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章