欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java實現(xiàn)字符串的分割(基于String.split()方法)

 更新時間:2022年09月30日 10:26:20   作者:虛假編程30年的老師傅  
Java中的我們可以利用split把字符串按照指定的分割符進(jìn)行分割,然后返回字符串?dāng)?shù)組,下面這篇文章主要給大家介紹了關(guān)于Java實現(xiàn)字符串的分割的相關(guān)資料,是基于jDK1.8版本中的String.split()方法,需要的朋友可以參考下

前言

本章對Java如何實現(xiàn)字符串的分割,是基于jDK1.8版本中的String.split()方法。

本文篇幅較長,內(nèi)容較為復(fù)雜涉及到許多小細(xì)節(jié),都是我在使用時候以及查閱資料時候遇到的坑,建議反復(fù)觀看??!

內(nèi)容中含有對源碼的解讀,如果可以建議詳細(xì)讀懂源碼,有助于對split的理解使用。

最后,長文警告,可按需觀看?。?/p>

一、JDK-1.8-API文檔說明(推薦閱讀)

首先對java-JDK-1.8的文檔進(jìn)行解讀,以下是我從文檔中截取的兩張圖片,分別是關(guān)于split單參數(shù)方法與split雙參數(shù)方法,如下圖:

對以上內(nèi)容提煉重點:

  • 該方法是將字符串分割的方法,通過給定的String regex作為分割符分割。分割后生成一個字符串?dāng)?shù)組,該數(shù)組中子字符串的排序為他們在原字符串中的順序。
  • 如果沒有找到對應(yīng)的分隔符(regex)則返回一個長度為1的字符串?dāng)?shù)組,僅存放原字符串
  • 對于單個參數(shù)的方法有:該方法是調(diào)用了限制參數(shù)(limit)為0的雙參數(shù)split方法
  • 對于雙參數(shù)的方法有:limit是控制模式應(yīng)用的次數(shù)因此限定了輸出字符串?dāng)?shù)組的長度,并給出三種分類:

1)limit>0:模式最多應(yīng)用n-1次,數(shù)組的長度不大于n,數(shù)組的最后一個條目將包含超出匹配分隔符的所有輸入
2)limit<0:模式將被應(yīng)用到盡可能多的次數(shù),且數(shù)組可以有任何長度
3)limit=0:模式將被應(yīng)用到盡可能多的次數(shù),且數(shù)組可以有任何長度,并且尾隨的空字符串將被丟棄

二、簡單的使用

了解完jdk文檔提供的基礎(chǔ)使用方法,接下來進(jìn)行以下簡單的一個對于split方法的入門使用,首先是對于單個字符作為分隔符的使用以及對于使用正則表達(dá)式分割

1、單個字符分隔

/**
  * 輸出分隔后的字符數(shù)組
  * 為了可以明顯的看出空字符串的輸出,如遇空字符串則輸出為——“空字符串”
  * @param split
  */
    private void printSplit(String[] split) {
        for (String temp : split) {
            //空字符串的話輸出--“空字符串”
            if (temp.equals("")) {
                System.out.println("空字符串");
            } else {
                System.out.println(temp);
            }
        }
    }

	/**
     * 基礎(chǔ)使用1:單個字符-:
     */
    @Test
    public void Test1() {
        string = "boo:and:foo";
        String[] split = string.split(":");
        printSplit(split);
    }

    /**
     * 基礎(chǔ)使用1:單個字符-o
     */
    @Test
    public void Test2() {
        string = "boo:and:foo";
        String[] split = string.split("o");
        printSplit(split);
    }

Test1運行結(jié)果:

Test2運行結(jié)果:

通過單個字符的分割可以看出,基本使用還是比較簡單的,但是在第二個分割字符“o”時產(chǎn)生了一定的問題,就是分割到重復(fù)的字符“o”會在中間出現(xiàn)一個空字符串,以及尾部的空字符串居然并沒有被分割進(jìn)去

2、正則表達(dá)式

/**
  * 基礎(chǔ)使用2:正則表達(dá)式-1
  */
    @Test
    public void Test3() {
        string = "asd-sdf+sda+sda";
		//匹配-或者+
        String[] split = string.split("[-\\+]");
        printSplit(split);
    }

/**
  * 基礎(chǔ)使用2:正則表達(dá)式-2
  */
    @Test
    public void Test4() {
        string = "boo1:a2nd:fo3o";
		//匹配正整數(shù)
        String[] split = string.split("[0-9]*[1-9][0-9]*");
        printSplit(split);
    }

Test3運行結(jié)果:

Test4運行結(jié)果:

對于正則表達(dá)式的分割成功了,證明split中參數(shù)String regex是可以支持輸入正則表達(dá)式進(jìn)行分割

三、Java源碼分析

以下源碼比較繞,建議是跟著下面的測試代碼一邊調(diào)試一邊理解(ps:源碼英文已轉(zhuǎn)譯)。

比較難的說明文字后面都有以下都會有一小部分的總結(jié),如果實在看不懂看總結(jié)也可以~

/**
* 單個參數(shù)的方法其實就是調(diào)用了雙參數(shù)的方法,第二個參數(shù)limit為0
*/
public String[] split(String regex) {
	return split(regex, 0);
}

public String[] split(String regex, int limit) {
    
    /*英文轉(zhuǎn)譯:
    如果正則表達(dá)式是
    (1)一個字符的字符串,并且這個字符不是
    正則表達(dá)式的元字符".$|()[{^?* + \ \”,或
    (2)兩個字符的字符串,第一個字符是反斜杠和
    第二個不是ascii數(shù)字或ascii字母。*/
    
    //下面有對于if判斷的拆解,因為篇幅占位大,放到本段代碼末尾,建議先看   
    char ch = 0;
    if (((regex.value.length == 1 &&
          ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
         (regex.length() == 2 &&
          regex.charAt(0) == '\\' &&
          (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
          ((ch-'a')|('z'-ch)) < 0 &&
          ((ch-'A')|('Z'-ch)) < 0)) &&
        (ch < Character.MIN_HIGH_SURROGATE ||
         ch > Character.MAX_LOW_SURROGATE))
     //以上這一大片都是if判斷條件↑
    {
        //定義上一個字符串分割結(jié)束的位置,起始為0
        int off = 0;
   		//定義下一個分隔符在待分割字符串中的位置,,起始為0
        int next = 0;
        //boolean值,如果limit大于0為true ,小于等于0皆為false
        boolean limited = limit > 0;
        //定義分割后的字符串?dāng)?shù)組,因為String[]長度固定,不便于使用
        ArrayList<String> list = new ArrayList<>();
        
      /**
        * while判斷語句中做了兩件事:
        *	1)使用indexof查詢off以后下一個ch的位置,并賦值給next
        *	2)如果后續(xù)再找不到ch則退出循環(huán)
        *
        *if語句中也不簡單,首先看【 !limited 】
        *上面limited賦值中可知,如果limit大于0,則【!limited】恒為false
        *					如果limit不大于于0,則【!limited】恒為true
        *翻譯為“人話”就是:
        *   如果limit大于0則后續(xù)條件才需要判斷,否則if條件一直都是true
        *   進(jìn)一步推論,如果limit不大于0,則else里面的語句塊肯定不會執(zhí)行
        *
        *其次看看第二個條件,【list.size() < limit - 1】:list的長度小于limit-1
        *我們可以做出兩種假設(shè):
        *	1)limit無限大,則這第二個條件一定恒為true
        *	2)limit很小,那么只有這種情況才會出現(xiàn)list長度會小于limit的情況,也就是false
        *	那么limit的分界線在哪呢?也就是limit的取值如何才會出現(xiàn)有false的情況
        *	決定性因素肯定就是 原字符串分割出多少子字符串:
        *	若limit是大于能分割出的子字符串,表達(dá)式一定為true
        *	若limit是小于能分割出的子字符串個數(shù),那表達(dá)式【list.size()=limit-1】則為false,并且進(jìn)入else語句塊。
        *
        *將兩個條件整合到一起:也就是只有當(dāng)limit>0并且小于能分割出子字符串個數(shù)時
        *if才會出現(xiàn)false的情況,并且這時【list.size()=limit-1】,進(jìn)入else語句塊
        *
        *if{...}else{...}里面的語句塊就比較簡單了
        *	通過substring進(jìn)行分割字符串,并放入list中
        *	然后將off往后移動
        *	else內(nèi)的語句塊也是一樣的,不過添加的是最后一個子字符串
        */
        while ((next = indexOf(ch, off)) != -1) {
            if (!limited || list.size() < limit - 1) {
                list.add(substring(off, next));
                off = next + 1;
            } else {    // last one
                //assert (list.size() == limit - 1);
                list.add(substring(off, value.length));
                off = value.length;
                break;
            }
        }
        // If no match was found, return this
        //如果沒有找到匹配項,則返回this
        //off如果為0,那么就證明上述那個循環(huán)中并未找到匹配項
        if (off == 0)
            return new String[]{this};

        // Add remaining segment
        //添加剩余的部分
        //同上,當(dāng)limit不大于0的時候恒為true
        //只有l(wèi)imit>0而且list長度大于等于limit才為false
        //因為上面循環(huán)中l(wèi)ist.size()=limit-1,進(jìn)入else語句塊,語句塊中會再給list加入一個元素
        
        //可知,這個if判斷與上面else語句塊兩個互補(bǔ),兩個不會同時運行到
        //這個與else語句塊作用一致,都是將最后一個子字符串添加入list
        if (!limited || list.size() < limit)
            list.add(substring(off, value.length));

        // Construct result
        //構(gòu)建結(jié)果
        
        //如果limit為0,進(jìn)行特殊處理
        //首先字符串?dāng)?shù)組長度大于0并且獲取最后一個字符數(shù)組的字符串長度為0
        //簡而言之,前提條件字符數(shù)組長度得大于0(小于0還分割個啥)
        //其次尋找最后一個是否是空字符串,如果是,將長度減一,如果不是則退出循環(huán)
        int resultSize = list.size();
        if (limit == 0) {
            while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
                resultSize--;
            }
        }
        
        //定義字符數(shù)組,將list轉(zhuǎn)為String[]
        //因為后面空字符長度被去掉了,于是空字符被省略了
        String[] result = new String[resultSize];
        return list.subList(0, resultSize).toArray(result);
    }
    //如果不符合if的條件就進(jìn)入這個方法
    return Pattern.compile(regex).split(this, limit);
}

//if條件的拆分
 /*如果正則表達(dá)式是
    (1)一個字符的字符串,并且這個字符不是
    正則表達(dá)式的元字符".$|()[{^?* + \ \”,或
    (2)兩個字符的字符串,第一個字符是反斜杠和
    第二個不是ascii數(shù)字或ascii字母。*/
(
    (
        (
            regex.value.length == 1
            &&
            ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1
            //小細(xì)節(jié),這里將ch賦值了,也就是將改字符賦值給了ch
        )
        ||
        (
            regex.length() == 2 
            &&
            regex.charAt(0) == '\\'
            &&
            (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0
            //小細(xì)節(jié)*2
            &&
            ((ch-'a')|('z'-ch)) < 0
            &&
            ((ch-'A')|('Z'-ch)) < 0
        )
    )
    &&
    (ch < Character.MIN_HIGH_SURROGATE ||ch > Character.MAX_LOW_SURROGATE)
)

1、源代碼的測試代碼

建議進(jìn)入調(diào)試模式配合上面代碼同步運行,有利于對代碼的解讀

    /**
     * 讀源碼:測試1,單個非特殊字符
     * 結(jié)果為并未調(diào)用Pattern.compile
     * if判斷條件結(jié)果為true
     */
    @Test
    public void Test5() {
        string = "boo:and:foo";
        String[] split = string.split(":");
        printSplit(split);
    }

    /**
     * 讀源碼:測試1,兩個字符,并且第一個字符為\第二個字符不為數(shù)字或者單詞
     * 結(jié)果為并未調(diào)用Pattern.compile
     * if判斷條件結(jié)果為true
     * 這里需要注意,雖然regex是為\\$但是其實在Java解讀中第一個為轉(zhuǎn)義字符
     * 所以傳到方法中其實代碼解讀為\$
     * 你們可以在調(diào)試的時候看一下這個入?yún)⒌闹当隳馨l(fā)現(xiàn)
     */
    @Test
    public void Test6() {
        string = "boo$and$foo";
        String[] split = string.split("\\$");
        printSplit(split);
    }

    /**
     * 讀源碼:測試3,三個字符
     * if判斷條件結(jié)果為false
     * 結(jié)果為調(diào)用了Pattern.compile
     */
    @Test
    public void Test7() {
        string = "boo:and:foo";
        String[] split = string.split("and");
        printSplit(split);
    }

2、源代碼運行原理圖示

下圖為以":"作為分隔符的運行圖示

3、解讀完代碼后的總結(jié)(推薦閱讀)

1.if可以進(jìn)入的條件為單個字符并且不為正則表達(dá)式元字符,或者雙字符,第一個為反斜杠并且第二個字符不為數(shù)字與字母,如此一來,其實第二個條件就是允許輸入正則表達(dá)式元字符,其實整個if條件就是如果是單個字符就可以允許輸入,但是為了遵循正則表達(dá)式的規(guī)則才設(shè)置了兩個字符的條件。

結(jié)論:String.split()這個方法對于單個字符(包括特殊字符,但是需要轉(zhuǎn)義)是自己進(jìn)行分割的,但是如果是**多個字符,這個方法就會去調(diào)用Pattern.compile(regex).split(this, limit);**這個方法

如果需要多次使用split方法并且都是多個字符作為分隔符,直接使用Pattern.compile(regex).split(this, limit);或許會帶來更高的效率

2.內(nèi)部采用substring()進(jìn)行字符串的分割,然后傳入list集合內(nèi)部,于是如果待分割字符串中分隔符連續(xù)出現(xiàn)就會出現(xiàn)分割出空字符串,詳情可見上面使用“o”進(jìn)行分割出現(xiàn)了一個空字符串,會出現(xiàn)substring(n,n) 這種情況結(jié)果為空字符串

3.如果使用limit =0 的雙參數(shù)方法,區(qū)別于limit <0,split會在生成結(jié)果前檢查后端的空字符串并將其去掉,這就是為什么limit = 0的時候后面的空字符串會被丟棄

四、limit參數(shù)使用區(qū)別

1、limit=0

那么模式將被應(yīng)用盡可能多的次數(shù),數(shù)組可以是任何長度,并且結(jié)尾空字符串將被丟棄。

就是會首先運行出全部分割出的子字符串然后再將后面結(jié)尾的空格去掉

    /**
     * limit參數(shù)區(qū)別:=0
     * 輸出全部結(jié)果,去除結(jié)果后面全部空字符數(shù)組
     */
    @Test
    public void Test8() {
        string = "boo:and:foo:::";
        String[] split = string.split(":", 0);
        printSplit(split);
    }

Test8運行結(jié)果:

2、limit<0

模式將被應(yīng)用盡可能多的次數(shù),而且數(shù)組可以是任何長度。

分割出全部子字符串包含有全部分割結(jié)果

    /**
     * limit參數(shù)區(qū)別:<0
     * 輸出全部結(jié)果
     */
    @Test
    public void Test9() {
        string = "boo:and:foo:::";
        String[] split = string.split(":", -1);
        printSplit(split);
    }

Test9運行結(jié)果:

3、limit>0

模式將被最多應(yīng)用 n - 1 次,數(shù)組的長度將不會大于 n,而且數(shù)組的最后一項將包含所有超出最后匹配的定界符的輸入。

分割出的字符串長度只會小于等于limit,當(dāng)limit小于能分割出的子字符串?dāng)?shù)量時,這個時候數(shù)組長度等于limit

如果limit大于能分割出的子字符串?dāng)?shù)量時,數(shù)組長度等于子字符串?dāng)?shù)量,小于limit

    /**
     * limit參數(shù)區(qū)別:>0 --小于分割出的字符數(shù)組長度
     */
    @Test
    public void Test10() {
        string = "boo:and:foo";
        String[] split = string.split(":", 2);
        printSplit(split);
    }

    /**
     * limit參數(shù)區(qū)別:>0 --大于分割出的字符數(shù)組長度
     */
    @Test
    public void Test11() {
        string = "boo:and:foo";
        String[] split = string.split(":", 5);
        printSplit(split);
    }

Test10運行結(jié)果:

Test11運行結(jié)果:

五、易錯點(推薦閱讀)

1、分割到第一個字符

當(dāng)?shù)谝粋€字符被分割到,則字符數(shù)組首個字符串為空

原因分析:在源碼中可以看出,源碼使用indexof進(jìn)行查找下一個分隔符的位置,當(dāng)找到分隔符為第一個的時候就會將next賦值為0,然后使用substring分割,于是兩個參數(shù)就變成了subtring(0,0)必然分割出一個空字符串出來

如果開頭的這個空字符串并非想要的理想輸出,只能自己手動去除

    /**
     * 易錯點:分割到第一個字符
     */
    @Test
    public void Test12() {
        string = "boo$and$foo";
        String[] split = string.split("b", 0);
        printSplit(split);
    }

Test12運行結(jié)果:

2、轉(zhuǎn)義字符\

java中使用\必須再次進(jìn)行一次轉(zhuǎn)義,例如用“\\”代表“\”,并且正則表達(dá)式元字符都必須轉(zhuǎn)義才能作為分隔符

原因分析:split這個方法其實可以看出還是推薦我們使用正則表達(dá)式進(jìn)行分割的,在寫String regex這個參數(shù)我建議還是看著正則表達(dá)式的書寫方法進(jìn)行書寫的

源碼中明確給出說明,正則表達(dá)式元字符前面都需要使用\轉(zhuǎn)義——.$|()[{^?*+\

其次,java中\(zhòng)的使用也必須進(jìn)行轉(zhuǎn)義,在Java中雙反斜杠表示一個反斜杠,書寫中應(yīng)該特別注意

推薦書寫方法:先找個正則表達(dá)式驗證的網(wǎng)站驗證正則表達(dá)式的書寫,然后復(fù)制進(jìn)去java代碼中,需要注意的是,在java 1.7之后將帶有\(zhòng)的字符串粘貼到雙引號中會自動再添加一個\

    /**
     * 易錯點:轉(zhuǎn)義字符\
     */
    @Test
    public void Test13() {
        //因為java代碼不能直接輸入一個反斜杠,必須進(jìn)行轉(zhuǎn)義,這里的\\表達(dá)為\
        string = "boo\\and\\foo";
        //這里\\\\應(yīng)該拆開看成為\\ \\,前面兩個代表一個\后面兩個代表一個\
        //實際\\\\表達(dá)的含義應(yīng)該為\\,對應(yīng)正則表達(dá)式的語法\\表達(dá)為\
        //所以在Java代碼中\(zhòng)\\\在最終處理時候其實表達(dá)為\
        String[] split = string.split("\\\\", 0);
        printSplit(split);
    }

    /**
     * 易錯點:轉(zhuǎn)義字符\
     */
    @Test
    public void Test14() {
        string = "boo+and-foo*boo";
        //這里的+-*都是正則表達(dá)式的元字符,都需要使用\轉(zhuǎn)義,然后在Java中再對\轉(zhuǎn)義
        //原正則表達(dá)式[\+\-\*]
        String[] split = string.split("[\\+\\-\\*]", 0);
        printSplit(split);
    }

Test13運行結(jié)果:

Test14運行結(jié)果:

3、正則表達(dá)式修飾符不可用

基于運行測試發(fā)現(xiàn)正則表達(dá)式的修飾符在split中使用是無效的,使用的時候注意避開

    /**
     * 易錯點:正則表達(dá)式修飾符不可用
     * 理想輸出[(boo:),(nd:foo)]
     */
    @Test
    public void Test15() {
        string = "boo:and:foo";
        String[] split = string.split("/[a]/g", 0);
        printSplit(split);
    }

Test15運行結(jié)果:

總結(jié)

到此這篇關(guān)于Java實現(xiàn)字符串的分割的文章就介紹到這了,更多相關(guān)Java字符串分割內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot Scheduling定時任務(wù)的示例代碼

    SpringBoot Scheduling定時任務(wù)的示例代碼

    springBoot提供了定時任務(wù)的支持,通過注解簡單快捷,對于日常定時任務(wù)可以使用。本文詳細(xì)的介紹一下使用,感興趣的可以了解一下
    2021-08-08
  • Hibernate單表操作實例解析

    Hibernate單表操作實例解析

    這篇文章主要介紹了Hibernate單表操作實例解析,分享了相關(guān)代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下
    2018-02-02
  • SpringBoot返回統(tǒng)一的JSON標(biāo)準(zhǔn)格式實現(xiàn)步驟

    SpringBoot返回統(tǒng)一的JSON標(biāo)準(zhǔn)格式實現(xiàn)步驟

    這篇文章主要介紹了SpringBoot返回統(tǒng)一的JSON標(biāo)準(zhǔn)格式,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-08-08
  • 深入學(xué)習(xí)java中的Groovy 和 Scala 類

    深入學(xué)習(xí)java中的Groovy 和 Scala 類

    本文將探討三種下一代 JVM 語言:Groovy、Scala 和 Clojure,比較并對比新的功能和范例,讓 Java 開發(fā)人員對自己近期的未來發(fā)展有大體的認(rèn)識。,需要的朋友可以參考下
    2019-06-06
  • MyBatis分頁插件PageHelper的具體使用

    MyBatis分頁插件PageHelper的具體使用

    這篇文章主要介紹了MyBatis分頁插件PageHelper的具體使用,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-02-02
  • spring boot打包成可執(zhí)行jar包

    spring boot打包成可執(zhí)行jar包

    本篇文章主要介紹了spring boot打包成可執(zhí)行jar包,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • Java的幾個重要版本_動力節(jié)點Java學(xué)院整理

    Java的幾個重要版本_動力節(jié)點Java學(xué)院整理

    jdk8 將在2014年3月份發(fā)布,迄今為止,可能是最大更新的java版本,也是令人期待的一個版本,在Java中引入閉包概念對Java程序開發(fā)方法的影響甚至?xí)笥贘ava5中引入的泛型特征對編程方式帶來的影響
    2017-06-06
  • Java實現(xiàn)簡易學(xué)生管理系統(tǒng)

    Java實現(xiàn)簡易學(xué)生管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了Java實現(xiàn)簡易學(xué)生管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • Java中的圖形界面重繪方式

    Java中的圖形界面重繪方式

    這篇文章主要介紹了Java中的圖形界面重繪方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • OpenFeign在傳遞參數(shù)為對象類型是為空的問題

    OpenFeign在傳遞參數(shù)為對象類型是為空的問題

    這篇文章主要介紹了OpenFeign在傳遞參數(shù)為對象類型是為空的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03

最新評論