- 好好學Java:從零基礎到項目實戰
- 歐陽燊
- 3240字
- 2022-07-27 19:15:06
5.3.1 利用正則串分割字符串
除了前述的字符串處理方法外,還有一種分割字符串的場景也很常見,就是按照某個規則將字符串切割為若干子串。分割規則通常是指定某個分隔符,根據字符串內部的分隔符將字符串分割,例如逗號、空格等都可以作為字符串的分隔符。正好String類型提供了split方法用于切割字符串,只要字符串變量調用split方法,并把分隔符作為輸入參數,該方法即可返回分割好的字符串數組。
下面的split調用代碼例子將演示如何按照逗號和空格切割字符串(完整代碼見本章源碼的src\com\string\regular\RegexSplit.java):
// 通過逗號分割字符串 private static void splitByComma() { String commaStr="123,456,789"; String[] commaArray=commaStr.split(","); //利用split方法指定按照逗號切割字符串 for (String item : commaArray) { //遍歷并打印分割后的字符串數組元素 System.out.println("comma item=" + item); } } // 通過空格分割字符串 private static void splitBySpace() { String spaceStr="123 456 789"; String[] spaceArray=spaceStr.split(" "); //利用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的字符串數組。也就是說,原始串被逗號分割一次后又被空格分割一次,這樣一共分割兩次,最終得到了3個子串。下面的代碼將演示使用正則串“,| ”切割字符串的效果:
// 利用豎線同時指定多個串來分割字符串 private static void splitByMixture() { String mixtureStr="123,456 789"; // 正則串里的豎線表示“或”,豎線左邊和右邊的字符都可以用來分割字符串 String[] mixtureArray=mixtureStr.split(",| "); for (String item : mixtureArray) { // 遍歷并打印分割后的字符串數組元素 System.out.println("mixture item="+item); } }
當然,正則串中的保留字符不僅包括點號和豎線,還包括好多常見的符號,比如加號(+)、星號(*)、橫線(-),在正則串中均需轉義。其中,加號的正則轉義符為“\\+”,星號的正則轉義符為“\\*”,橫線的正則轉義符為“\\-”。這樣來看,加減乘除的四則運算符號只有除法的斜桿符(/)、取余數的百分號(%)無須轉義處理。倘若有一個字符串,要求以四則運算的5個符號進行切割,則需通過豎線把這幾個轉義后的字符加以連接,構成形如“\\+|\\*|\\-|/|%”的正則串。于是按照加減乘除與取余數符號切割字符串的代碼就變為下面這樣:
// 通過算術的加減乘除符號來分割字符串 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這10個數字使用豎線隔開 //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;"; // 正則串里的加號表示可以有一到多個前面的字符 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); } }
- 解構產品經理:互聯網產品策劃入門寶典
- 深入淺出WPF
- 算法精粹:經典計算機科學問題的Python實現
- Oracle Database 12c Security Cookbook
- Julia Cookbook
- PhoneGap Mobile Application Development Cookbook
- Jupyter數據科學實戰
- C++新經典
- Hands-On Full Stack Development with Go
- Visual Basic程序設計實踐教程
- Keras深度學習實戰
- Python全棧數據工程師養成攻略(視頻講解版)
- Scala Data Analysis Cookbook
- Visual Basic 6.0程序設計實驗教程
- PHP編程基礎與實踐教程