JAVA中String的split方法

我的個人網站:
http://riun.xyz


以下源碼版本:JDK1.8

簡介

Java 中 String 的 split 方法可以將字符串根據指定的間隔進行切割,例如字符串 str = “1,23,4,5” 經過 str.split(",") 切割後得到的返回值是一個字符串數組 String[] = [1, 23, 4, , 5],這種處理方式可以適配大多數場景。

問題

今天寫一個讀取csv文件的時候,發現一個小問題。【csv,一種文本文件格式,每行中的數據以逗號分隔,在windows平臺可以使用excel打開,打開後和普通excel顯示並無差別】

我處理的文件中存在這樣的一行數據:

,,,,f02e843b-a328-4023-bbbd-7ce075a29bef,,,2.00422E+19,,3000,12,6,2020/10/22,1,245.05,56.34,0,301.39,245.05,56.34,0,0,301.39,0,0,0,0,,0,0,NULL,,,,,,,,,,,,,,,,,,,,

使用BufferedReader.readLine()去讀取一行,然後用逗號分隔:str.split(","),最後發現拿到 的字符串數組中,前面的空串數據存在,後面的空串數據都消失了。即split切割後剩下的數據:

,,,,f02e843b-a328-4023-bbbd-7ce075a29bef,,,2.00422E+19,,3000,12,6,2020/10/22,1,245.05,56.34,0,301.39,245.05,56.34,0,0,301.39,0,0,0,0,,0,0,NULL

(後面的空串沒了,到NULL結束了)

由於csv文件中,每列數據都對應的有key,例如第一列爲id,第二列爲name,等等,所以即使是空串也必須存在,不能丟失。

分析

在看過split源碼後發現,String的split方法有兩個重載方法:public String[] split(String regex)public String[] split(String regex, int limit)

而調用split(String regex)方法時,內部是直接調用的 split(regex, 0),如下圖:
在這裏插入圖片描述

split(regex, 0)中,進行字符串的切割。

源碼裏,切割後又做了其他事情,如下:

int resultSize = list.size();
if (limit == 0) {
    while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
        resultSize--;
    }
}

其中list儲存結果數據。

如果我們使用split(regex)的話,會調用split(regex,0)那麼就是說我們不傳入limit參數,limit默認爲0。所以這裏會進入if語句。

進入後,就開始從後向前循環(resultSize爲結果元素長度,所以是從後向前),如果是空串(length==0),就清除掉此數據(resultSize–)。

注意由於這裏是 && 符號連接,所以當循環時遇到不爲空串,就立即跳出while了。所以此過程清除掉的數據是結尾處的所有空串。

,,,a,bss,cas,,fq,try,,h,,,, 這個字符串使用split(",")切割後,留下的數據是,,,a,bss,cas,,fq,try,,h,在從後向前循環時碰到第一個不爲空串的數據 h 就會停止,然後返回。

而我們想要讓split不清除數據,拿到分隔後的原始數據時怎麼辦呢?看代碼知道應該傳入limit,讓limit!=0,這樣就不會進入if語句,不會執行這些清除空串數據的代碼。那麼limit的值應該傳入什麼呢?下面進行幾個小實驗:

# 1、
String str = ",,,a,bss,cas,,fq,try,,h,,,,";
String[] split2 = str.split(",", 1); # limit爲1
System.out.println(Arrays.toString(split2));
System.out.println("長度爲"+split2.length);

>[,,,a,bss,cas,,fq,try,,h,,,,] # 此處是一個串
>長度爲1
    
# 2、
String str = ",,,a,bss,cas,,fq,try,,h,,,,";
String[] split2 = str.split(",", 5); # limit爲5
System.out.println(Arrays.toString(split2));
System.out.println("長度爲"+split2.length);

>[, , , a, bss,cas,,fq,try,,h,,,,] # 此處是5個串,分別爲:空串,空串,空串,a,bss,cas,,fq,try,,h,,,,
>長度爲5
    
# 3、
String str = ",,,a,bss,cas,,fq,try,,h,,,,";
String[] split2 = str.split(",", Integer.MAX_VALUE); # limit爲Integer.MAX_VALUE
System.out.println(Arrays.toString(split2));
System.out.println("長度爲"+split2.length);

>[, , , a, bss, cas, , fq, try, , h, , , , ] # 此處將所有串都拿到了,沒有清除數據。
>長度爲15

當傳入負數時,偶爾會運行成功,大多數情況下,會報以下錯誤:
在這裏插入圖片描述

結論

我們可以分析出,傳入limit爲正數時,split就不會幫我們清除掉它認爲無用的數據,而是將limit作爲結果長度的最大值進行切割。而當傳入limit爲0時,split會幫我們切割掉後面的空串。所以limit的含義是切割後結果的閥值(最大值),幫我們限制切割後結果的長度,limit爲0時就走JAVA自己定的規則(清除結尾處的空串)。

所以當我們的使用場景需要全部數據時,要使用兩個參數的split方法手動傳入limit,建議limit的值爲Integer.MAX_VALUE,這樣可以在不知道結果長度的情況下保證結果正確。

split(regex,limit)方法的完整結構大概可分三段解釋,如圖:
在這裏插入圖片描述

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