轉(zhuǎn)義字符
在字符表中有兩大類字符集捍靠,一類是Control Character,一類是Printable Character森逮。
對于可打印的字符榨婆,直接用其本身來表示例如,大小寫字母褒侧、所有數(shù)字良风、所有的標點符號和一些其他符號。
而Control Character該怎么表示闷供?在Java中可以用編碼來表示烟央,例如\u0000表示空字符;也可以使用轉(zhuǎn)義字符歪脏,例如制表符'\t'疑俭。
轉(zhuǎn)義字符
轉(zhuǎn)義字符是一種以“\”開頭的字符。例如退格符用'\b'表示婿失,換行符用'\n'表示钞艇。轉(zhuǎn)義字符中的''表示它后面的字符已失去它原來的含義,轉(zhuǎn)變成另外的特定含義豪硅。反斜杠與其后面的字符一起構(gòu)成一個特定的字符哩照。
轉(zhuǎn)義字符是表示字符的一種特殊形式。轉(zhuǎn)義字符以反斜''開頭懒浮,后面跟一個字符或一個八進制或十六進制數(shù)表示飘弧。轉(zhuǎn)義字符具有特定的含義,不同于字符原有的意義砚著,故稱轉(zhuǎn)義字符眯牧。
注意轉(zhuǎn)義字符是一個字符,并不是字符序列赖草。
通常使用轉(zhuǎn)義字符表示ASCII碼字符集中不可打印的控制字符和特定功能的字符学少。
特定功能字符指的是在程序設(shè)計語言中,一個字符表示特別的含義秧骑,而失去了原本的意義版确。如用于表示字符常量的單撇號(')扣囊,用于表示字符串常量的雙撇號(")和反斜杠(\)等。
這樣就很好理解為什么用"."分割字符串時绒疗,必須使用"\."侵歇。調(diào)用String.split()
方法時傳入的第一個參數(shù)是正則表達式模版。而在正則表達式語法中"."表示特定的含義:匹配除換行符 \n 之外的任何單字符吓蘑。要匹配 . 惕虑,請使用 . 。磨镶。而反斜杠在Java中也具有特定含義(具體什么含義不知道...大概是用來構(gòu)成轉(zhuǎn)義字的吧)溃蔫,所以要表示反斜杠字符就應(yīng)該寫成'\'。這樣一來就構(gòu)成了"\."琳猫。
Java中轉(zhuǎn)義字符表
轉(zhuǎn)義字符 | 含義 |
---|---|
'\60'伟叛、'\101'、'\141'分別表示字符'0'脐嫂、'A'和'a' | 八進制轉(zhuǎn)義字符统刮。它是由反斜杠''和隨后的1~3個八進制數(shù)字構(gòu)成的字符序列 |
'\u0000'表示空字符 | 可以在字符直接量中使用 Unicode 轉(zhuǎn)義序列,該轉(zhuǎn)義序列由六個 ASCII 字符組成:\u 加上一個四位數(shù)值的十六進制數(shù)账千。 |
'\r'侥蒙、'\n'、'\b'匀奏、'\t'辉哥、'\f',分別表示回車攒射,換行醋旦,退格,制表会放,換頁 | 控制字符饲齐,也就是Unicode中第一類字符 |
'\'、'''咧最、'"'捂人,分別表示反斜杠,單引號矢沿,雙引號 | 特定功能字符滥搭,在程序設(shè)計語言中具有特別含義的字符,從而通過轉(zhuǎn)義字符表達原本含義 |
可能對于八進制轉(zhuǎn)義字符用途不是很理解捣鲸。字符'0'瑟匆、'A'和'a'的ASCII碼的八進制值分別為60、101和141栽惶。字符集中的所有字符都可以用八進制轉(zhuǎn)義字符表示愁溜。
網(wǎng)上文章中還指出下列轉(zhuǎn)義字符:
點的轉(zhuǎn)義:. ==> u002E
美元符號的轉(zhuǎn)義:$ ==> u0024
乘方符號的轉(zhuǎn)義:^ ==> u005E
左大括號的轉(zhuǎn)義:{ ==> u007B
左方括號的轉(zhuǎn)義:[ ==> u005B
左圓括號的轉(zhuǎn)義:( ==> u0028
豎線的轉(zhuǎn)義:| ==> u007C
右圓括號的轉(zhuǎn)義:) ==> u0029
星號的轉(zhuǎn)義:* ==> u002A
加號的轉(zhuǎn)義:+ ==> u002B
問號的轉(zhuǎn)義:? ==> u003F
雖然沒有完全試驗過疾嗅,但是嘗試了一個
String str = "Java轉(zhuǎn)義字符(補遺)";
str = str.replace("\(補遺\)", "");
System.out.println(str);
執(zhí)行代碼會提示錯誤: 非法轉(zhuǎn)義符
,說明這些字符在Java中并沒有特殊含義冕象,不需要轉(zhuǎn)義代承。至于為什么會造成這種錯覺應(yīng)該是正則表達式原因。如"\."這里面轉(zhuǎn)義的是反斜杠渐扮,并不是'.'论悴。
參考
正則表達式
概述
正則表達式(regular expression)描述了一種字符串匹配的模式,可以用來檢查一個串是否含有某種子串墓律、將匹配的子串做替換或者從某個串中取出符合某個條件的子串等膀估。
構(gòu)建正則表達式
用多種元字符與運算符將小的表達式結(jié)合在一起來創(chuàng)建更大的表達式。
正則表達式的組件可以是單個的字符只锻、字符集合玖像、字符范圍紫谷、字符間的選擇或者所有這些組件的任意組合齐饮。
正則表達式是由普通字符(例如字符 a 到 z)以及特殊字符(稱為"元字符")組成的文字模式。模式描述在搜索文本時要匹配的一個或多個字符串笤昨。正則表達式作為一個模板祖驱,將某個字符模式與所搜索的字符串進行匹配。
普通字符
普通字符主要指的是在正則表達式語法中沒有被指定為特殊含義(這些字符被稱為元字符)的所有字符(包括非打印字符瞒窒,也就是Control Character)捺僻。包含了所有大小寫字母、數(shù)字崇裁、所有標點符號和一些其他符號匕坯。
Control Character
正則表達式中的Control Character轉(zhuǎn)義字符
字符 | 描述 |
---|---|
\cx | 匹配由x指明的控制字符。例如拔稳, \cM 匹配一個 Control-M 或回車符葛峻。x 的值必須為 A-Z 或 a-z 之一。否則巴比,將 c 視為一個原義的 'c' 字符术奖。 |
\f | 匹配一個換頁符。等價于 \x0c 和 \cL轻绞。 |
\n | 匹配一個換行符采记。等價于 \x0a 和 \cJ。 |
\r | 匹配一個回車符政勃。等價于 \x0d 和 \cM唧龄。 |
\s | 匹配任何空白字符,包括空格奸远、制表符选侨、換頁符等等掖鱼。等價于 [ \f\n\r\t\v]。 |
\S | 匹配任何非空白字符援制。等價于 [^ \f\n\r\t\v]戏挡。 |
\t | 匹配一個制表符。等價于 \x09 和 \cI晨仑。 |
\v | 匹配一個垂直制表符褐墅。等價于 \x0b 和 \cK。 |
表格中類似
\x0c
都是ASCII表中字符十六進制編碼洪己。
元字符
元字符也就是正則表達式中具有特定功能的字符妥凳,主要有限定符,定位符答捕,其他元字符逝钥。如果需要在匹配字符中包含這些元字符,那么必須轉(zhuǎn)義拱镐,也就是轉(zhuǎn)義字符'\元字符'
艘款。
限定符
限定符用來指定正則表達式的一個給定組件必須要出現(xiàn)多少次才能滿足匹配。
字符 | 描述 |
---|---|
* | 匹配前面的子表達式零次或多次沃琅。例如哗咆,zo* 能匹配 "z" 以及 "zoo"。* 等價于{0,}益眉。 |
+ | 匹配前面的子表達式一次或多次晌柬。例如,'zo+' 能匹配 "zo" 以及 "zoo"郭脂,但不能匹配 "z"年碘。+ 等價于 {1,}。 |
? | 匹配前面的子表達式零次或一次展鸡。例如屿衅,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等價于 {0,1}娱颊。 |
{n} | n 是一個非負整數(shù)傲诵。匹配確定的 n 次。例如箱硕,'o{2}' 不能匹配 "Bob" 中的 'o'拴竹,但是能匹配 "food" 中的兩個 o。 |
{n,} | n 是一個非負整數(shù)剧罩。至少匹配n 次栓拜。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o幕与。'o{1,}' 等價于 'o+'挑势。'o{0,}' 則等價于 'o*'。 |
{n,m} | m 和 n 均為非負整數(shù)啦鸣,其中n <= m潮饱。最少匹配 n 次且最多匹配 m 次。例如诫给,"o{1,3}" 將匹配 "fooooood" 中的前三個 o香拉。'o{0,1}' 等價于 'o?'。請注意在逗號和兩個數(shù)之間不能有空格中狂。 |
*凫碌、+和?
都是貪婪限定符,它們會盡可能多的匹配子表達式胃榕。在它們后面加上?
就可以實現(xiàn)最小匹配盛险。舉個例子
public class TestQualifier {
public static void main(String[] args) {
String s = "<H1>Chapter 1 – Introduction to Regular Expressions</H1>";
System.out.println(s);
String s1 = s.replaceAll("<.*>", "");//1
System.out.println(s1);
String s2 = s.replaceAll("<.*?>", "");//2
System.out.println(s2);
}
}
Console輸出結(jié)果:
可以明顯看到區(qū)別。第一次替換由于貪婪限定符的存在勋又,將整個字符串替換成""苦掘。第二次替換采用了非貪婪限定符,實現(xiàn)最小匹配赐写,只是將<H1>
和</H1>
替換成""鸟蜡。
定位符
定位符能夠?qū)⒄齽t表達式固定到行首或行尾膜赃。它們還能夠創(chuàng)建這樣的正則表達式挺邀,這些正則表達式出現(xiàn)在一個單詞內(nèi)、在一個單詞的開頭或者一個單詞的結(jié)尾跳座。
字符 | 描述 |
---|---|
^ | 匹配輸入字符串開始的位置端铛。如果設(shè)置了 RegExp 對象的 Multiline 屬性,^ 還會與 \n 或 \r 之后的位置匹配疲眷。 |
$ | 匹配輸入字符串結(jié)尾的位置禾蚕。如果設(shè)置了 RegExp 對象的 Multiline 屬性,$ 還會與 \n 或 \r 之前的位置匹配狂丝。 |
\b | 匹配一個字邊界换淆,即字與空格間的位置。 |
\B | 非字邊界匹配几颜。 |
注意倍试,不能將限定符與定位點一起使用。由于在緊靠換行或者字邊界的前面或后面不能有一個以上位置蛋哭,因此不允許諸如 ^* 之類的表達式县习。
其他元字符
字符 | 描述 |
---|---|
( ) | 標記一個子表達式的開始和結(jié)束位置。子表達式可以獲取供以后使用。 |
. | 匹配除換行符 \n 之外的任何單字符躁愿。 |
[ | 標記一個中括號表達式的開始叛本。 |
\ | 將下一個字符標記為或特殊字符、或原義字符彤钟、或向后引用来候、或八進制轉(zhuǎn)義符。 |
^ | 匹配輸入字符串的開始位置逸雹,除非在方括號表達式中使用吠勘,此時它表示不接受該字符集合。 |
{ | 標記限定符表達式的開始峡眶。 |
豎直線 | 指明兩項之間的一個選擇剧防。 |
\d | 匹配一個數(shù)字字符。等價于 [0-9]辫樱。 |
\D | 匹配一個非數(shù)字字符峭拘。等價于 [^0-9]。 |
\w | 匹配包括下劃線的任何單詞字符狮暑。等價于'[A-Za-z0-9_]'鸡挠。 |
\W | 匹配任何非單詞字符。等價于 '[^A-Za-z0-9_]'搬男。 |
\xn | 匹配 n拣展,其中 n 為十六進制轉(zhuǎn)義值。十六進制轉(zhuǎn)義值必須為確定的兩個數(shù)字長缔逛。例如备埃,'\x41' 匹配 "A"。'\x041' 則等價于 '\x04' & "1"褐奴。正則表達式中可以使用 ASCII 編碼按脚。 |
\un | 匹配 n,其中 n 是一個用四個十六進制數(shù)字表示的 Unicode 字符敦冬。例如辅搬, \u00A9 匹配版權(quán)符號 (?)。 |
\xn | 匹配 n脖旱,其中 n 為十六進制轉(zhuǎn)義值堪遂。十六進制轉(zhuǎn)義值必須為確定的兩個數(shù)字長。例如萌庆,'\x41' 匹配 "A"溶褪。'\x041' 則等價于 '\x04' & "1"。正則表達式中可以使用 ASCII 編碼踊兜。 |
\nml | 如果 n 為八進制數(shù)字 (0-3)竿滨,且 m 和 l 均為八進制數(shù)字 (0-7)佳恬,則匹配八進制轉(zhuǎn)義值 nml。 |
表格中有提到正則表達式可以使用ASCII編碼于游,而Java采用的是UTF-16字符集(16位的Unicode字符集)毁葱。也就是說正則表達式模版中可以使用ASCII編碼代替字符,但是是使用ASCII編碼轉(zhuǎn)換成相應(yīng)的字符贰剥。
public class TestRegexHex {
public static void main(String[] args) {
String str = "12A34B567N89M";
str = str.replaceAll("[\\x41-\\x5A]", " ");
System.out.println(str);
}
}
Console輸出:12 34 567 89
倾剿。如果要匹配Unicode字符,則必須通過\un形式匹配(n就是十六進制數(shù)字蚌成,表示字符對應(yīng)的Unicode編碼)前痘。
這部分理解好像有點問題
子表達式
限定符表格中可以看到一個限定符( )
,它就是用來創(chuàng)建子表達式担忧。子表達式可以有自己的匹配模式芹缔。例如do(es)?
可以匹配"do"或者"does";(T|t)h(E|e)
可以匹配"ThE"or"The"or"thE"or"the"瓶盛。
注意限定符[ ]
制定的匹配模式是匹配該集合中的一個字符最欠。并不是全部字符。
反向引用
允許在同一正則表達式的后部引用前面的子表達式惩猫。
所匹配的每個子表達式的字符序列都按照在正則表達式模式中從左到右出現(xiàn)的順序存儲芝硬。緩沖區(qū)編號從 1 開始,最多可存儲 99 個捕獲的子表達式轧房。每個緩沖區(qū)都可以使用 '\n' 訪問拌阴,其中 n 為一個標識特定緩沖區(qū)的一位或兩位十進制數(shù)。
因為子表達式可以嵌套另一個子表達式奶镶,所以它的位置是參與計數(shù)的左括號的位置迟赃。例如,正則表達式
/([Jj]ava([Ss]cript)?)\sis\s(fun\w*)/
中实辑,嵌套的子表達式([Ss]cript)可以用\2來指代捺氢。
可以使用非捕獲元字符 '?:'藻丢、'?=' 或 '?!' 來重寫捕獲剪撬,忽略對相關(guān)匹配的保存。如(?:pattern)
這里可能有個誤區(qū)悠反,引用的并不是匹配模式残黑,而是引用上一個表達式匹配后獲取的字符序列。保證引用的字符序列
匹配斋否。而且要緩存一定要使用()
限定符梨水。
通配符&正則表達式
通配符是系統(tǒng)命令使用,一般用來匹配文件名等系統(tǒng)命令操作茵臭。正則表達式是操作字符串疫诽。最明顯的差異,在通配符中*
通配符匹配零個或多個字符;在正則表達式中*
匹配前面的子表達式零次或多次奇徒。
參考
上述元字符表格參考自
正則表達式 - 語法
雏亚,是部分元字符,更多元字符可以參考該文章摩钙。
Java源文件編碼
測試一個Java源文件罢低,編碼格式為GBK,修改默認encoding參數(shù)為GBK編譯并運行胖笛。
import java.io.*;
public class TestEncoding {
/**
* Mac OS默認javac encoding 參數(shù)設(shè)置為UTF-8
* 從內(nèi)存中提取字符串采用的也是UTF-8編碼
* 最后控制臺顯示也是UTF-8
**/
public static void main(String[] args) {
String str = "生生世世";
System.out.println(str);
String s = null;
try {
s = new String(str.getBytes("GBK"));
}catch(UnsupportedEncodingException e) {
e.printStackTrace();
}
System.out.println(s);
}
}
大致的流程就是使用GBK編碼解碼源文件网持,將"生生世世"以Unicode存儲在內(nèi)存中。然后從內(nèi)存中以GBK編碼對內(nèi)存中"生生世世"Unicode進行編碼长踊,然后傳遞給控制臺功舀,最后控制臺使用UTF-8進行解碼成相應(yīng)的字符導(dǎo)致亂碼:生生世世 ????????
參考
Scanner
知識點
命令行執(zhí)行字節(jié)碼文件
當源文件中第一行指定了包名,且編譯時通過-d
指定放置生成的類文件位置后身弊,應(yīng)該在shell切換到包所在目錄下執(zhí)行java 包名.類名
命令日杈。例如源文件
package src.a.b;
import java.io.*;
import java.util.*;
public class TestScanner {
public static void main(String[] args) {
//File file = new File("../../Regex/src/TestEncoding.java");
//File file = new File("../Regex/src/TestEncoding.java");
File file = null;
String path = System.getProperty("user.dir");
System.out.println(path);
String[] pathArray = path.split("/");
for(String p : pathArray) {
System.out.println(p);
}
StringBuilder builder = new StringBuilder(32);
builder.append("/");
if(pathArray.length > 0) {
for(String p : pathArray) {
if(p.equals("workspace")){
builder.append(p);
break;
}
if(!p.isEmpty()) {
builder.append(p + "/");
}
}
file = new File(builder.toString(), "Regex/src/TestEncoding.java");
}else {
System.out.println("no file path!");
}
System.out.println(file.getPath());
InputStream input = null;
Scanner in = null;
try {
input = new FileInputStream(file);
in = new Scanner(input, "GBK");
// while(in.hasNextLine()) {
// System.out.println(in.nextLine());
// }
do{
System.out.println(in.nextLine());
}while(in.hasNextLine());
}catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
in.close();
}
}
}
包相對路徑是src/a/b
,而包所在目錄是Scanner
佑刷,應(yīng)當在該目錄下執(zhí)行java src.a.b.TestScanner
命令莉擒。Console輸出:
可以從第一條打印看出,當前路徑確實在Scanner下瘫絮。
參考
如何在代碼中獲取上級目錄
File類中有兩個方法getParent()
和getParentFile()
涨冀。這兩個方法都可以獲取上級目錄,唯一不同的是返回值麦萤。前者返回String鹿鳖,后者返回File實例。
那么現(xiàn)在的問題就是如何構(gòu)建當前文件路徑的File實例壮莹〕嶂模可以通過File file = new File(".")
來獲取當前工作目錄。這個目錄和System.getProperty("user.dir")
相同命满。
但是如果這個時候直接通過file對象調(diào)用getParent()
或者getParentFile()
返回值都是null涝滴。大概是因為不能用相對路徑來獲取上級目錄,這里就可以使用System.getProperty("user.dir")
返回的路徑來構(gòu)建一個File實例胶台,通過它來獲取上級目錄路徑或者File對象歼疮。
還有一種通過相對路徑獲取上級目錄File對象的方法File file = new File("..")
。
注意這里所有說的當前目錄都是執(zhí)行java命令行指令的目錄诈唬,并不是指當前源代碼的類文件路徑韩脏。
總結(jié)
File file = new File(".");
等價于System.getProperty("user.dir")
指的是當前工作目錄。
File file = new File("..");
指的是當前工作目錄上級目錄铸磅。想訪問上上級目錄可以使用../..
當實例File對象傳入的路徑字符串以"/"開頭赡矢,指定的是UNIX系統(tǒng)平臺根目錄杭朱。
參考
Scanner用途
在平時寫demo時吹散,主要用于獲取控制臺輸入胆描。當通過System.in創(chuàng)建一個Scanner掃描器時秕脓,控制臺會一直等待輸入,直到開發(fā)者敲擊回車鍵結(jié)束,把所有輸入對象傳遞給Scanner作為掃描對象简烤。要獲取輸入的內(nèi)容可以調(diào)用一系列nextXXX();
方法波闹。
不僅如此挡育,還可以為文件号杠,流,字符串等創(chuàng)建掃描器耸棒。以此來方便的逐段掃描內(nèi)容荒澡,并對掃描得到的內(nèi)容做一定的處理。而且還可以指定字符集解碼內(nèi)容与殃。
Scanner是根據(jù)正則表達式來分隔单山,nextLine()
根據(jù)系統(tǒng)平臺的行分隔符,而next()
默認分割符是空格(包括所有換行符幅疼,換頁符米奸,制表符,垂直制表符爽篷,回車符悴晰,空格),可以通過useDelimiter()
來自定義分割符逐工。
Scanner并不能移動控制臺的光標铡溪,只能夠在掃面內(nèi)容中移動±岷埃控制臺只會一直等待開發(fā)者輸入內(nèi)容直到敲擊回車鍵結(jié)束棕硫,然后把所有內(nèi)容傳遞給Scanner。
Scanner&BufferReader
由于Scanner是JDK1.5提供的袒啼,所以在此之前都是通過BufferedReader來獲取控制臺輸入哈扮。
public class TestBufferedInput{
public static void main(String[] args) throws Exception{
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter your name: ");
StringBuilder builder = new StringBuilder(32);
builder.append("Your name is " + reader.readLine());
System.out.println("Enter your age: ");
builder.append(",you are " + reader.readLine() + " years old.");
System.out.println("Enter your company: ");
builder.append("You work for " + reader.readLine() + ".");
System.out.println(builder.toString());
}
}
相比較Scanner,BufferedReader沒有那么簡便瘤泪,只能讀取一行或者單個字符灶泵,也可以使用read(char, int int)讀取多個字符。
但是BufferedReader是字符輸入流中讀取文本对途,緩沖各個字符,從而提供字符髓棋、數(shù)組和行的高效讀仁堤础惶洲!速度要比Scanner快!而且也可以設(shè)置緩沖區(qū)的大小膳犹,或者可使用默認的大小恬吕。大多數(shù)情況下,默認值就足夠大了须床。
Scanner取得輸入數(shù)據(jù)的依據(jù)是空白字符:如空格铐料、制表符、回車符豺旬、換行符钠惩、換頁符,Scanner就會返回下一個輸入族阅。
參考
Scanner和BufferedReader的區(qū)別和用法
字符串分割
Java默認的分割符是空白字符:制表符篓跛,回車符,換行符坦刀,空格愧沟,換特符
String.split()
一般字符串分割處理第一時間想到的就是split()
方法,可以直接傳入正則表達式進行處理鲤遥,返回一個數(shù)組沐寺。實現(xiàn)起來非常方便,但是效率很低盖奈。
public static String[] splitByStringSplit(String s, String regex) throws Exception{
String[] strArray = s.split(regex);
if(strArray.length > 0) {
return strArray;
}else {
throw new Exception("Can't split string with this regex!");
}
}
split(String, int limit)方法中的limit參數(shù)芽丹,限制分割數(shù)目。
split()分割完全是按照正則表達式卜朗,并不回去不區(qū)分字符串中的標識符拔第、數(shù)和帶引號的字符串,它們也不識別并跳過注釋场钉。
StringTokenizer
第二種可以使用效率較高的StringTokenizer來分割蚊俺。是JDK專門用來提供分割字符串處理的工具類」渫颍可以根據(jù)自定義delim(分割符)進行處理泳猬,并將結(jié)果進行封裝提供對應(yīng)方法進行遍歷取值。
它有三種構(gòu)造函數(shù):
- StringTokenizer(String str)宇植,使用Java 默認的分割符得封,不返回分割符。
- StringTokenizer(String str, String delim)指郁,使用自定的分割符構(gòu)造StringTokenizer對象忙上,但是不返回分割符。
- StringTokenizer(String str, String delim, boolean returnDelims)闲坎,使用zidingyi的分割符構(gòu)造StringTokenizer對象疫粥,同時可以指定是否返回分割符茬斧。
常用方法:
- hasMoreTokens();判斷字符串中是否還有token。
- nextToken();獲取下一個token梗逮。
- nextToken(String delim);返回當前分割符到下一個新的分割符之間的token项秉。
與split()類似按照指定或者默認的分割符去處理字符串。
public static String[] splitByStringTokenizer(String s, String delim) throws Exception{
StringTokenizer tokenizer = new StringTokenizer(s, delim);
List<String> strList = new ArrayList<>();
while(tokenizer.hasMoreTokens()) {
strList.add(tokenizer.nextToken());
}
int count = strList.size();
if(count > 0) {
return strList.toArray(new String[count]);
}else {
throw new Exception("Can't split string with this delim!");
}
}
substring()配合indexOf()高效分割處理
subString()是采用了時間換取空間技術(shù)慷彤,因此它的執(zhí)行效率相對會很快娄蔼,但是會造成內(nèi)存溢出問題,需要很好的處理內(nèi)存問題底哗。而indexOf()方法是一個執(zhí)行速度非乘晁撸快的方法。
public static String[] splitByStringSubstring(String s, String delim) throws Exception{
List<String> strList = new ArrayList<>();
do{
int index = s.indexOf(delim);
if(index < 0) {
break;
}
strList.add(s.substring(0, index));
if(index == s.length()) {
break;
}
s = s.substring(index + 1);
}while(!s.isEmpty());
int count = strList.size();
if(count > 0) {
return strList.toArray(new String[count]);
}else {
throw new Exception("Can't split string with this delim!");
}
}
三種方案比較
public class TestStringSplit{
public static void main(String[] args) throws Exception{
String str = "hello.java.delphi.asp.php";
String regex = "\\.";
String delim = ".";
long startTime = 0;
long endTime = 0;
String[] strArray = null;
startTime = System.nanoTime();
strArray = StringSpilt.splitByStringSplit(str, regex);
endTime = System.nanoTime();
System.out.println("String split by split method: " + (endTime - startTime));
startTime = System.nanoTime();
strArray = StringSpilt.splitByStringTokenizer(str, delim);
endTime = System.nanoTime();
System.out.println("String split by StringTokenizer: " + (endTime - startTime));
startTime = System.nanoTime();
strArray = StringSpilt.splitByStringSubstring(str, delim);
endTime = System.nanoTime();
System.out.println("String split by substring method: " + (endTime - startTime));
}
}
Console輸出:
String split by split method: 1671486
String split by StringTokenizer: 527509
String split by substring method: 87169
可見效率差距艘虎。