前面介紹了處理字元串的常用方法,還有一種分割字元串的場景也很常見,也就是按照某個規則將字元串切割為若幹子串。分割規則通常是指定某個分隔符,根據字元串內部的分隔符將字元串進行分割,例如逗號、空格等等都可以作為字元串的分隔符。正好String類型提供了split方法用於切割字元串,只要字元串變數調用sp ...
前面介紹了處理字元串的常用方法,還有一種分割字元串的場景也很常見,也就是按照某個規則將字元串切割為若幹子串。分割規則通常是指定某個分隔符,根據字元串內部的分隔符將字元串進行分割,例如逗號、空格等等都可以作為字元串的分隔符。正好String類型提供了split方法用於切割字元串,只要字元串變數調用split方法,並把分隔符作為輸入參數,該方法即可返回分割好的字元串數組。
下麵的split調用代碼例子演示瞭如何按照逗號和空格切割字元串:
// 通過逗號分割字元串 private static void splitByComma() { String commaStr = "123,456,789"; // 利用split方法指定按照逗號切割字元串 String[] commaArray = commaStr.split(","); for (String item : commaArray) { System.out.println("comma item = "+item); } } // 通過空格分割字元串 private static void splitBySpace() { String spaceStr = "123 456 789"; // 利用split方法指定按照空格切割字元串 String[] spaceArray = spaceStr.split(" "); for (String item : spaceArray) { System.out.println("space item = "+item); } }
除了逗號和空格以外,點號和豎線也常常用來分隔字元串,但是對於點號和豎線,split方法的調用代碼不會得到預期的結果。相反,split(".")無法得到分割後的字元串數組,也就是說結果的字元串數組為空;而split("|")分割得到的字元串數組,每個數組元素只有一個字元,其結果類似於toCharArray。究其原因,緣於split方法的輸入參數理應是個正則串,並非普通的分隔字元。由於點號和豎線都是正則串的保留字元,因此無法直接在正則串中填寫,必須進行轉義處理方可。如同回車符和換行符在普通字元串中通過首碼的反斜桿轉義那樣(回車符對應\r,換行符對應\n),正則字元串通過在原字元前面添加兩個反斜桿來轉義,像點號字元在正則串中對應的轉義符為“\\.”,而豎線在正則串中對應的轉義符為“\\|”。經過轉移處理之後,通過點號和豎線切割字元串的正確代碼寫法如下所示:
// 通過點號分割字元串 private static void splitByDot() { String dotStr = "123.456.789"; // split(".")無法得到分割後的字元串數組 //String[] dotArray = dotStr.split("."); // 點號是正則串的保留字元,需要進行轉義(在點號前面加兩個反斜桿) String[] dotArray = dotStr.split("\\."); for (String item : dotArray) { System.out.println("dot item = "+item); } } // 通過豎線分割字元串 private static void splitByLine() { String lineStr = "123|456|789"; // split("|")分割得到的字元串數組,每個數組元素只有一個字元,類似於toCharArray的結果 //String[] lineArray = lineStr.split("|"); // 豎線是正則串的保留字元,需要進行轉義(在豎線前面加兩個反斜桿) String[] lineArray = lineStr.split("\\|"); for (String item : lineArray) { System.out.println("line item = "+item); } }
豎線符號之所以被定為正則串的保留字元,是因為它在正則表達式里起到了“或”的判斷作用,例如正則串“,| ”表示逗號和空格都是滿足條件的分隔符;一個字元串如果同時包含一個逗號和一個空格,那麼按照“,| ”切割的結果將是長度為3的字元串數組;也就是說,原始串被逗號分割一次後又被空格分割一次,這樣一共分割兩次最終得到了三個子串。下麵的代碼演示了使用正則串“,| ”切割字元串的效果:
// 利用豎線同時指定多個串來分割字元串 private static void splitByMixture() { String mixtureStr = "123,456 789"; // 正則串里的豎線表示“或”,豎線左邊和右邊的字元都可以用來分割字元串 String[] mixtureArray = mixtureStr.split(",| "); for (String item : mixtureArray) { System.out.println("mixture item = "+item); } }
當然,正則串中的保留字元不僅包括點號和豎線,還包括好些常見的符號,比如加號(+)、星號(*)、橫線(-),在正則串中均需進行轉義。其中加號的正則轉義符為“\\+”,星號的正則轉義符為“\\*”,橫線的正則轉義符為“\\-”。這麼估摸下,加減乘除的四則運算符號,只有除法的斜桿符(/)、取餘數的百分號(%)無需轉義處理。倘若有個字元串,要求以四則運算的五個符號進行切割,則需通過豎線把這幾個轉義後的字元加以連接,構成形如“\\+|\\*|\\-|/|%”的正則串。於是按照加減乘除符號切割字元串的代碼就變為下麵這樣:
// 通過算術的加減乘除符號來分割字元串 private static void splitByArith() { String arithStr = "123+456*789-123/456%789"; // 正則串里的加號、星號、橫線都要轉義,加減乘除符號之間通過豎線隔開 String[] arithArray = arithStr.split("\\+|\\*|\\-|/|%"); for (String item : arithArray) { System.out.println("arith item = "+item); } }
分割用的正則串,不單單是一個個字元,還支持好幾個字元組成的字元串。譬如“(1)”、“(2)”、“(3)”都可以作為分隔串,註意圓括弧內部的數字可以是0到9,如此一來,從“(0)”到“(9)”的分隔串合集豈不是要寫成以下這般:“(0)|(1)|(2)|(3)|(4)|(5)|(6)|(7)|(8)|(9)”?然而以上正則串的寫法有兩個錯誤:
1、圓括弧也是正則表達式的保留字元,所以不能直接在正則串中書寫“(”和“)”,而必須寫成轉義形式“\\(”和”“\\)”。
2、作為保留字元的圓括弧,其作用類似數值計算之時的圓括弧,都是通過圓括弧把括弧內外的運算區分開。而豎線符號“|”的或運算優先順序不如圓括弧,因此每逢複雜一點的或運算,應當把圓括弧放在整個邏輯運算式子的外面。
綜合以上兩點,修正之後的正則串應該改成下列形式:“\\((0|1|2|3|4|5|6|7|8|9)\\)”。可是該式子的豎線太多,意思僅僅是獲取0到9之間的某個數字之一,針對這種情況,正則表達式引入了另外一種簡化的寫法,即通過方括弧包裹0123456789,形如“\\([0123456789]\\)”,同樣指代0到9之間的某個數字,從而省略了若幹個豎線。進一步說,日常生活中0到9,常常寫做“0-9”,於是對應更簡單的正則串“\\([0-9]\\)”。
其實0到9正好涵蓋了所有的一位數字,對於一位數字而言,正則表達式提供了專門的表達式“\\d{1}”。式子前面的“\\d”代表某個數字,式子後面的“{1}”代表字元數量是1位。推而廣之,“\\d{2}”表示兩位數字,“\\d{3}”表示三位數字,等等。像這個正則例子只有一位數字,甚至尾巴的“{1}”都可以去掉,因為“\\d”預設就是一位數字。
一口氣介紹了許多種從0到9的正則表達串,接下來不妨逐一驗證這些正則串是否有效,驗證用的代碼例子如下所示:
// 通過圓括弧及其內部數字來分割字元串 private static void splitByBracket() { String bracketStr = "(1)123;(2)456;(3)789;"; // 圓括弧也是正則串的保留字元,0到9這九個數字使用豎線隔開 //String[] bracketArray = bracketStr.split("\\((0|1|2|3|4|5|6|7|8|9)\\)"); // 利用方括弧聚集一群字元,表示這些字元之間是“或”的關係,故而可省略豎線 //String[] bracketArray = bracketStr.split("\\([0123456789]\\)"); // 連續的數字可使用橫線連接首尾數字,例如“0-9”表示從0到9之間的所有數字 //String[] bracketArray = bracketStr.split("\\([0-9]\\)"); // 利用“\\d”即可表達0到9的數字,後面的{1}表示1位數字,依此類推{3}表示三位數字 //String[] bracketArray = bracketStr.split("\\(\\d{1}\\)"); // “\\d”預設就是1位數字,此時後面的{1}可直接略去 String[] bracketArray = bracketStr.split("\\(\\d\\)"); for (String item : bracketArray) { System.out.println("bracket item = "+item); } }
上述的幾種正則串,只能表達從“(0)”到“(9)”的分隔串,然而圓括弧內部還可能是兩位數字或者三位數字,比如“(10)”、“(12)”、“(001)”這樣。對於數字位數不固定的情況,可以把“\\d”改為“\\d+”,末尾多出來的加號,表示前面的字元允許有一位,也允許有多位。此時正則串添加了加號的字元串切割代碼見下:
// 通過特殊符號的加號來分割字元串 private static void splitWithPlus() { String bracketStr = "(1)123;(2)456;(13)789;"; // 正則串里的加號表示可以有1到多個前面的字元 String[] bracketArray = bracketStr.split("\\(\\d+\\)"); for (String item : bracketArray) { System.out.println("plus item = "+item); } }
上面說的位數不固定,畢竟至少還有一位。假設現在某個字元不但位數不確定,甚至還可能沒有該字元(位數為0),採用寫法“\\d+”就無法奏效了。要想滿足位數可有可無的情況,需將末尾的加號換成星號,也就是改成“\\d*”,此時改用星號的字元串切割代碼變為下麵這般:
// 通過特殊符號的星號來分割字元串 private static void splitWithStar() { String bracketStr = "()123;(2)456;(13)789;"; // 正則串里的星號表示可以有0到多個前面的字元 String[] bracketArray = bracketStr.split("\\(\\d*\\)"); for (String item : bracketArray) { System.out.println("star item = "+item); } }
到目前位置,分隔符還僅限於標點和數字,如果引入英文字母作為分隔串,又該如何書寫呢?註意英文字母區分大小寫,因而使用“a-z”表示所有的小寫字母,使用“A-Z”表示所有的大寫字母。如果採納“(a)”、“(B)”、“(c)”這種大小寫混合的分隔串,就得通過正則串“\\([a-zA-Z]\\)”來表達,對應的字元串切割代碼如下所示:
// 通過大小寫字母來分割字元串 private static void splitWithLetter() { String bracketStr = "(a)123;(B)456;(c)789;"; // 在正則串中表達小寫字母和大寫字母 String[] bracketArray = bracketStr.split("\\([a-zA-Z]\\)"); for (String item : bracketArray) { System.out.println("letter item = "+item); } }
現在有個麻煩的業務場景,圓括弧內部不但可能是數字和字母,還可能是其它標點符號,這下難不成把眾多標點符號一個個羅列出來?要知道標點符號可沒有“0-9”、“a-z”、“A-Z”的簡單寫法噢。不過這難不倒強大的正則表達式,因為點號作為正則的保留字元,它代表了除回車\r和換行\n以外的其它字元,所以使用“\\(.\\)”即可表達符合要求的任意字元了,當然是被圓括弧包裹著的、除了回車\r和換行\n以外的任意字元。下麵便是匹配前述場景的字元串切割代碼例子:
// 通過特殊符號的點號來分割字元串 private static void splitWithDot() { String bracketStr = "(1)123;(B)456;(%)789;"; // 正則串里的點號表示除了回車\r和換行\n以外的其它字元 String[] bracketArray = bracketStr.split("\\(.\\)"); for (String item : bracketArray) { System.out.println("dot item = "+item); } }
更多Java技術文章參見《Java開發筆記(序)章節目錄》