Java 之路 (十三) -- 字符串(String、正則表達(dá)式)

個人吐槽:對于這章,第一遍讀和重讀之后果然看法不同:第一次讀時覺得,文章用了大篇幅來介紹 API,這樣我可以比較容易理解這個方法是干嘛的,以此理解這個類是干嘛的;但是重讀之后覺得,文章居然用了這么大篇幅在講 API(尤其是正則表達(dá)式),如果我需要知道具體某個方法怎么用,直接去官方文檔查多好啊,這種情況下,我更希望得到某個方法可能出現(xiàn)的坑,而不只是方法的介紹(畢竟,這往往需要踩過坑之后總結(jié)的,hhh)。


1. String 基礎(chǔ)

1.1 String 不可變

  • String 對象是不可變的。(只讀性)

  • String 類中每一個修改 String 值的方法,實(shí)際上都是創(chuàng)建了一個新的 String 對象,原有的 String 對象絲毫未動。

1.2 String 的連接問題

"+" 和 "+=" 是經(jīng)過 Java 重載之后的兩個操作符,可用來對 String 拼接。

同時 Java 不允許程序員重載任何操作符。

String + String 與 StringBuilder.append() 對比

  1. 直接相加字符串(不含 String 引用,形如"hello"+"world"):效率最高,簡單來說,其全部為常量,編譯期就會優(yōu)化為 "helloworld",編譯期值就已經(jīng)確定了。

  2. 間接相加字符串(含 String 引用,如 str + "world"):效率最差,簡單來說會取出原有 String 與 "world" 進(jìn)行拼接,然后將結(jié)果存入另一個新的 String 對象中,雖然編譯器進(jìn)行了優(yōu)化,通過 StringBuilder.append() 來實(shí)現(xiàn)拼接,但是當(dāng)出現(xiàn)循環(huán)時,會出現(xiàn) StringBuilder 對象的反復(fù)生成。

  3. StringBuilder.append():介于上述二者之間。

    綜上:

    1. 如果是固定字符串如“xxx”,那么直接用 "+" 即可。
    2. 如果間接相加字符串,但是次數(shù)很少,則 StringBuilder 和 "+" 都可,差別不很大
    3. 如果簡介相加字符串,且多次循環(huán),那么強(qiáng)烈建議 StringBuilder

1.3 無意識的遞歸

當(dāng)想要打印出某對象的內(nèi)存地址時,應(yīng)該調(diào)用 Object.toString() / super.toString() 方法,而非 this 上的 toString()。

換句話說,就是當(dāng)前對象重寫的 toString() 方法中,應(yīng)該調(diào)用 super.toString() 而不是使用 this。

在當(dāng)前對象的 toString() 方法中,如果調(diào)用 this,會發(fā)生自動類型轉(zhuǎn)換,將對象類型轉(zhuǎn)換為 String 類型。那么怎么轉(zhuǎn)換呢?正式通過調(diào)用 this (當(dāng)前對象)上的 toString() 方法。

em...完美的形成一個遞歸,自己調(diào)用自己,且沒有終止條件。

1.4 String API

這里有想知道的一切 API

https://docs.oracle.com/javase/9/docs/api/java/lang/String.html

1.5 格式化輸出

如下幾種方式:

  1. System.out.println() 強(qiáng)行湊成指定形式,不推薦

  2. System.out.format():針對于 PrintStream 和 PrintWriter,其中包括 System.out 對象

  3. Formatter 類:可以看作是一個翻譯器,將格式化字符串與數(shù)據(jù)翻譯成需要的結(jié)果。

    1. 格式化說明符:%[argument_index$][flags][width][.precision]conversion

      width 指定域的最小尺寸

      precision 指定最大尺寸,適用于 String 和浮點(diǎn)數(shù),無法用于整數(shù)

    2. 常用的類型轉(zhuǎn)換

      類型轉(zhuǎn)換字符 意義 類型轉(zhuǎn)換字符 意義
      d 十進(jìn)制整數(shù)型 e 科學(xué)計數(shù)浮點(diǎn)數(shù)
      c Unicode 字符 x 十六進(jìn)制整數(shù)
      b Boolean 值 h 十六進(jìn)制散列碼
      s String % 字符 "%"
      f 十進(jìn)制浮點(diǎn)數(shù)

      更多詳見 https://docs.oracle.com/javase/9/docs/api/java/util/Formatter.html

  4. String.format()

    1. 實(shí)際上就是內(nèi)部封裝了 Formatter 對象,然后將傳入的參數(shù)傳遞給 Formatter,由它來進(jìn)行具體的處理。

2. 正則表達(dá)式

2.1 通用正則表達(dá)式

就不整理出來了,放上一篇教程

http://www.runoob.com/regexp/regexp-tutorial.html

https://docs.oracle.com/javase/9/docs/api/java/util/regex/Pattern.html

補(bǔ)充一點(diǎn):

  • 在 java 中,"\\" 表示一個有效的 "\",因此如果需要表示正則表達(dá)式里的一個數(shù)字 "\d",需要寫成 "\\d"

2.2 Pattern & Matcher

接口 CharSequence 從 CharBuffer、String、String Buffer、StringBuilder 類之中抽象出了字符序列的一般化定義:

interface CharSequence {
    charAt(int i);
    length();
    subSequence(int start,int end);
    toString();
}

本小節(jié)簡單介紹 Java 中如何處理正則表達(dá)式:

2.2.1 基礎(chǔ)使用:

step 1:Pattern.compile(regex) 編譯 String 類型的 regex,并產(chǎn)生 Pattern 對象

step 2:Pattern.matcher(待檢索的字符串)生成一個 Matcher 對象

直接上例子,通過例子說明:

import java.util.regex;

public class TestRegularExpression {
    public static void main(String[] args) {
        String[] array = {"aabbcc", "aab", "aab+", "(b+)"};
        
        for (String arg : array) {
            System.out.println();
            print("Regular expression: \"" + arg + "\"");
            Pattern p = Pattern.compile(arg); // step1: Pattern 表示編譯后的匹配模型Pattern.(編譯后的正則表達(dá)式)
            Matcher m = p.matcher("aabbcc"); // step2: 模型實(shí)例 檢索 待匹配字符串并 生成一個匹配對象Matcher, Matcher有很多方法
            while (m.find()) {
                print("Match \"" + m.group() // 待匹配的字符串
                                 + "\" at positions " 
                                 + m.start() // 字符串匹配regex的起始位置
                                 + "-" + (m.end() - 1)); // 字符串匹配regex的終點(diǎn)位置
            }
        }
    }

Pattern 對象表示編譯后的正則表達(dá)式,重點(diǎn)在于 Matcher 對象,它提供了一系列方法來進(jìn)行正則的匹配,下面簡單介紹:

詳見 https://docs.oracle.com/javase/9/docs/api/overview-summary.html

  1. Matcher.find():用來在 CharSequence 查找多個匹配

  2. Matcher.group():用來獲取與組相關(guān)的信息

    組是用括號劃分的正則表達(dá)式,可以用組的編號來引用某個組,組0表示整個表達(dá)式,組1表示被第一隊(duì)括號括起來的組。。。

    A(B(C))D : 組0是 ABCD,組1是B,組2是C

  3. Matcher.start() & end():返回先前匹配的起始和截止位置的索引。

  4. Pattern 標(biāo)記:重載方法,Pattern.compile(String regex, int flags) 接受一個 flags 參數(shù),來調(diào)整匹配的行為。具體看官方文檔:

    https://docs.oracle.com/javase/9/docs/api/java/util/regex/Pattern.html

  5. split():將輸入字符串?dāng)嚅_成字符串對象數(shù)組。

  6. 替換 replacexxx():替換文本

  7. reset():將現(xiàn)有的 Matcher 對象應(yīng)用于一個新的字符序列。

3. 掃描輸入

Scanner 是 Java SE5 中添加的特性,主要就是減輕掃描輸入的工作負(fù)擔(dān),最實(shí)用的是獲取控制臺輸入,其他比如從文件讀取內(nèi)容的,emmm...感覺有些雞肋。

舉個使用的簡單例子:

public class SimpleScanner { 
        public static void main(String[] args) { 
                Scanner s = new Scanner(System.in); 
                System.out.println("請輸入字符串:"); 
                while (true) { 
                        String line = s.nextLine(); 
                        if (line.equals("exit")) break; 
                        System.out.println(">>>" + line); 
                } 
        } 
}

/*
請輸入字符串:
whdalive
>>>whdalive
exit

Process finished with exit code 0
*/

Scanner 使用很方便,這是因?yàn)樗臉?gòu)造器可以接受任何類型的輸入對象,有了 Scanner 之后,所有輸入、分詞以及翻譯的操作都隱藏在不同類型的 next 方法中。

3.1 Scanner 定界符

默認(rèn)情況下,Scanner 根據(jù)空白字符對輸入進(jìn)行分詞,但是我們可以用正則表達(dá)式指定自己所需的定界符。

public static void main(String[] args) throws FileNotFoundException { 
    Scanner s = new Scanner("12,42,78,99,42"); 
    s.useDelimiter(","); 
    while (s.hasNext()) { 
        System.out.println(s.next()); 
    } 
}
/*輸出
12
42
78
99
42
*/

我們通過 useDelimiter() 方法來指定定界符,顯然上述代碼中我們使用的是逗號。

3.2 正則表達(dá)式掃描

Scanner 的 next 方法中,有一個重載方法可以接收 String 的正則表達(dá)式,此時它會找到下一個匹配該模式的輸入部分,然后調(diào)用 match() 方法就可以獲得匹配的結(jié)果。工作方式和正則表達(dá)式匹配是類似的。

但是需要注意一點(diǎn):它僅僅針對下一個輸入分詞進(jìn)行匹配,如果正則表達(dá)式中有定界符,那么永遠(yuǎn)不可能匹配成功。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容