<small id="7ktuj"></small>
      <bdo id="7ktuj"></bdo>
        <mark id="7ktuj"></mark>

        <source id="7ktuj"></source>
        <small id="7ktuj"></small>

        ITPub博客

        首頁 > 應用開發 > Java > String的split方法的使用

        String的split方法的使用

        原創 Java 作者:蝴蝶飛啊飛 時間:2019-10-23 11:52:22 0 刪除 編輯

        1. 引言

        split 方法很常用 , 記得我入職公司的時候 , 第一道筆試題就是關于字符串的拆分拼裝等 , 這也足以說明 , 大公司對這些方法的重視程度 .

        其實我們平時一般用到的都是這些方法最簡單的用法, 但如果你不了解他的實現原理 , 碰到某些特殊問題終究是會被卡住的 , 于是就產生了所謂的 bug, 而這也就是大神和菜鳥的區別之一吧 . 廣度是一方面 , 但真正看一個程序員是不是牛逼 , 重要的還是看他的深度 , 比如這個 split 的用法 , 如果你還停留在簡單的用法上 , 不妨看看后面 , 也看看你的深度 , 與君共勉 !

        2.split 用法

        先上一個例子:

        1. 最普通的用法

        String str1 = "aa,bb";

        String[] split1 = str1.split(",");

        System.out.println(split1.length);

        // 這個結果是 2, 都知道的

        2. 比較普通的用法

        String str2 = "";

        String[] split2 = str2.split(",");

        System.out.println(split2.length);

        // 這個結果是 1, 但部分人會認為這個的結果是 0,

        // 這個為什么是 1, 我會在后面說

        3. 看起來比較奇怪的用法

        String str3 = ",";

        String[] split3 = str3.split(",");

        System.out.println(split3.length);

        // 這個結果是 0, 但部分人會認為結果是 1, 部分人會認為結果是 2.

        // 這個又為什么是 0, 我也會在后面說

        3.split 源碼分析

        split 方法準確的來說有兩個參數 (String regex, int limit), 只不過平時我們用的 , split 的一個重載方法 (String regex), 默認是把第二個參數設置為 0, 源碼如下 :

        public String[] split(String regex) {

                return split(regex, 0);

            }

            public String[] split(String regex, int limit) {

        具體實現...

        }

        3.1. 參數解釋— regex

        1. 如果表達式不匹配輸入的任何內容,返回的數組只具有一個元素,即此字符串。(尤其注意空字符串這種情況,他也是一個字符串)

        2. 可以匹配的情況下,每一個字符串都由另一個匹配給定表達式的子字符串終止,或者由此字符串末尾終止(數組中的字符串按照他們在此字符串出現的順序排列)

        3.2. 參數解釋— limit

        該參數用于控制模式匹配使用的次數,可以影響到數組的長度

        1.limit>0:

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

        2.limit<0:

        模式匹配將應用盡可能多的次數,而且數組的長度是任何長度。

        3.lilmit=0:

        模式匹配將被應用盡可能多的次數,數組可以是任何長度,并且結尾空字符串將被丟棄。

        3.3. 不同 limit 值的情況下的 split 結果驗證

        假設有字符串aa,bcd,eef,

        3.3.1.limit=0,regex=","

        尾部的逗號,直接被忽略,頭部的逗號不會忽略

        String line = ",aa,bcd,eef,,,";

        String[] split = line.split(",",0);

        System.out.println(split.length);//4

        3.3.2.limit=2,regex=","

        總長度被限制成最大2

        String line = ",aa,bcd,eef,,,";

        String[] split = line.split(",",2);

        System.out.println(split.length);//2

        3.3.3.limit=100,regex=","

        總長度被限制成最大100

        但結果是7 個,說明當 limit 大于 0 ,并且遠大于應該有的長度時,頭部和尾部的逗號都沒有被忽略

        String line = ",aa,bcd,eef,,,";

        String[] split = line.split(",",100);

        System.out.println(split.length);//7

        3.3.4.limit=-1,regex=","

        結果是7 個,說明當 limit 小于 0 時,頭部和尾部的逗號都沒有被忽略

        String line = ",aa,bcd,eef,,,";

        String[] split = line.split(",",100);

        System.out.println(split.length);//7

        4. 擴展

        java.lang 包中有 String.split() 方法的原型是:

        public String[] split(String regex, int limit)

        split 函數是用于使用特定的切割符( regex )來分隔字符串成一個字符串數組,函數返回是一個數組。在其中每個出現 regex 的位置都要進行分解。

        需要注意是有以下幾點:

        1 regex 是可選項。字符串或正則表達式對象,它標識了分隔字符串時使用的是一個還是多個字符。如果忽略該選項,返回包含整個字符串的單一元素數組。

        2 limit 也是可選項。該值用來限制返回數組中的元素個數。

        3 )要注意轉義字符:“ . ”和“ | ”都是轉義字符,必須得加 "\\" 。同理: * + 也是如此的。

        如果用. ”作為分隔的話,必須是如下寫法:

        String.split("\\."), 這樣才能正確的分隔開,不能用 String.split(".");

        如果用| ”作為分隔的話,必須是如下寫法:

        String.split("\\|"), 這樣才能正確的分隔開,不能用 String.split("|");

        4 )如果在一個字符串中有多個分隔符,可以用“ | ”作為連字符,比如:“ acountId=? and act_id =? or extra=? , 把三個都分隔出來,可以用

        String.split("and|or");

        5 split 函數結果與 regex 密切相關,常見的幾種情況如下所示:

        public class SplitTest {

        public static void main(String[] args) {

        String str1 = "a-b";  

        String str2 = "a-b-";

        String str3 = "-a-b";

        String str4 = "-a-b-";

        String str5 = "a";

        String str6 = "-";

        String str7 = "--";

        String str8 = "";

        split(str1);

        split(str2);

        split(str3);

        split(str4);

        split(str5);

        split(str6);

        split(str7);

        split(str8);

        }

        public static void split(String demo){

        String[] array = demo.split("-");

        int len = array.length;

        System.out.print("\"" + demo + "\" 分割后的長度為: " + len);

        if(len >= 0)

        {

        System.out.print(", 分割后的結果為: ");

        for(int i=0; i<len; i++)

        {

        System.out.print(" \""+array[i]+"\"");

        }  

        }

        System.out.println();

        }

        }

        運行結果為:

        "a-b" 分割后的長度為: 2, 分割后的結果為: "a" "b"

        "a-b-" 分割后的長度為: 2, 分割后的結果為: "a" "b"

        "-a-b" 分割后的長度為: 3, 分割后的結果為: "" "a" "b"

        "-a-b-" 分割后的長度為: 3, 分割后的結果為: "" "a" "b"

        "a" 分割后的長度為: 1, 分割后的結果為: "a"

        "-" 分割后的長度為: 0, 分割后的結果為:

        "--" 分割后的長度為: 0, 分割后的結果為:

        "" 分割后的長度為: 1, 分割后的結果為: ""

        由此可以得出來:

        當字符串只包含分隔符時,返回數組沒有元素;

        當字符串不包含分隔符時,返回數組只包含一個元素(該字符串本身);

        字符串最尾部出現的分隔符可以看成外匯返傭http://www.fx61.com/不存在,不影響字符串的分隔;

        字符串最前端出現的分隔符將分隔出一個空字符串以及剩下的部分的正常分隔;

        不知道這么做的原因是什么,所以在使用split() 中需要注意這些問題,解決方法其實也挺簡單的,變通下即可。

        例如:

        String splitString = "\\|";

        String s = "|42345|||";

        s = s+"| ";

        String info[] = s.split(splitString);

        System.out.println(info.length);

        for (int i = 0; i < info.length; i++) {

        System.out.println(info[i]+"  >>>> " + i);

        }

        谷歌的guava 包,也有對 split 的重寫,返回的是 list 數組集合 .

        具體使用如下:

        <dependency>

                    <groupId>com.google.guava</groupId>

                    <artifactId>guava</artifactId>

                    <version>24.1-jre</version>

                </dependency>

        String line = ",aa,bcd,eef,,,";

        List<String> split2 = Splitter.on(",").splitToList(line);

        System.out.println(split2.size());//7

        根據結果,我們可以看到,谷歌的split 默認是頭部和尾部的逗號都沒有被忽略,相當于 java 包下 split limit 設置為 -1

        相比下,java 包下 split limit 默認不寫就是 0 ,即頭部逗號沒有被忽略,而尾部逗號是被忽略的

        一定要注意區分

        手寫String split() 方法, String split() 方法分三種情況:

        regex 只有一位,且不為列出的特殊字符;

        regex 有兩位,第一位位轉義字符且第二位不是數字和字母;

        最后一種情況就是正則表達式去拆分字符串。

        package com.dalingjia.algorithm.string;

        import com.google.common.collect.Lists;

        import org.junit.Test;

        import java.util.ArrayList;

        import java.util.List;

        import java.util.regex.Matcher;

        import java.util.regex.Pattern;

        /**

         * 手動實現 java split() 方法

         */

        public class SpiltUtil {

            private static final String contant = ".$|()[{^?*+\\";

            public static String[] splitMethod(String string, String regex){

                char ch = 0;

                int off = 0;

                int next = 0;

                ArrayList<String> list = Lists.newArrayList();

                if(regex.length() == 1 && contant.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)

                {

                    while ((next = string.indexOf(ch,off)) > 0){

                        list.add(string.substring(off, next));

                        off = next + 1;

                    }

                    if(off == 0){

                        return new String[]{string};

                    }

                    list.add(string.substring(off, string.length()));

                    return interceptEmpty(list);

                }

                return regexSplit(string, regex);

            }

            private static String[] regexSplit(String string, String regex) {

                int off = 0;

                // 將給定的正則表達式編譯到模式中

                Pattern pattern = Pattern.compile(regex);

                // 創建給定輸入與此模式匹配的匹配器

                Matcher m = pattern.matcher(string);

                List<String> list = Lists.newArrayList();

                while (m.find()){

                    //m.start(): 返回第一個匹配字符的索引

                    list.add(string.substring(off, m.start()));

                    //m.end(): 返回最后匹配字符之后的偏移量

                    off = m.end();

                }

                if(off == 0){

                    return new String[]{string};

                }

                list.add(string.substring(off, string.length()));

                return interceptEmpty(list);

            }

            // 截取空字符串

            private static String[] interceptEmpty(List<String> list){

                // 截取空的字符串

                int resultSize = list.size();

                while (resultSize>0 && list.get(resultSize-1).length() == 0){

                    resultSize--;

                }

                String[] strings = new String[resultSize];

                return list.subList(0, resultSize).toArray(strings);

            }

            // 測試方法

            @Test

            public void test() {

                // 測試 regex 只有一位,且不為列出的特殊字符

                String s1 = "gg,tge,hbfs,ijkd,,,";

                String[] strings1 = splitMethod(s1, ",");

                for (int i = 0; i < strings1.length; i++) {

                    System.out.println(strings1[i]);

                }

                // 測試 regex 有兩位,第一位位轉義字符且第二位不是數字和字母

                String s2 = "bb\'dn\'ags\'kl\'\'";

                String[] strings2 = splitMethod(s2,"\\'");

                for (int i = 0; i < strings2.length; i++) {

                    System.out.println(strings2[i]);

                }

                // 測試正則表達式

                String ss = "ac32dge533grhr139ljs343";

                String[] strings = splitMethod(ss,"[\\d]+");

                for (int i = 0; i < strings.length; i++) {

                    System.out.println(strings[i]);

                }

            }

        }

        String split() 方法源碼如下:

        public String[] split(String regex, int limit) {

                char ch = 0;

        if (

                        (   // 如果 regex 只有一位,且不為列出的特殊字符

                            (regex.length() == 1 && ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1)

                                    ||

                            // 如果 regex 2 位,第一位為轉義字符,且第二位不是數字或字母

                            /**

                             * || :    如果左邊計算后的操作數為 true, 右邊則不再執行,返回 true

                             *

                             * | ”:前后兩個操作數都會進行計算。也就是說:“ | ”不存在短路。

                             */

                            (regex.length() == 2 && regex.charAt(0) == '\\' && ( ((ch = regex.charAt(1))-'0')|('9'-ch) ) < 0 && ((ch-'a')|('z'-ch)) < 0 && ((ch-'A')|('Z'-ch)) < 0)

                        )

                                &&

                        /**

                         *  UTF-16 編碼中的 Unicode 高代理項代碼單元的最小值 , '\uD800'

                         *  UTF-16 編碼中的 Unicode 低代理項代碼單元的最大值 , '\uDFFF'

                         */

                        (ch < Character.MIN_HIGH_SURROGATE || ch > Character.MAX_LOW_SURROGATE)

                    ){

                    int off = 0;

                    int next = 0;

                    boolean limited = limit > 0;

                    ArrayList<String> list = new ArrayList<>();

                    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 (off == 0)

                        return new String[]{this};

                    // 添加最后一個子序列

                    if (!limited || list.size() < limit)

                        list.add(substring(off, value.length));

                    // 截取后面的空字符串

                    int resultSize = list.size();

                    if (limit == 0) {

                        while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {

                            resultSize--;

                        }

                    }

                    String[] result = new String[resultSize];

                    return list.subList(0, resultSize).toArray(result);

                }

                // 第三種情況,利用正則表達式去 split 字符串

                return Pattern.compile(regex).split(this, limit);

        }        

        String split() 方法最后一行調用的 Pattern split() 方法,二則源碼大同小異。

        源碼如下:

        public String[] split(CharSequence input, int limit) {

                int index = 0;

                boolean matchLimited = limit > 0;

                ArrayList<String> matchList = new ArrayList<>();

                Matcher m = matcher(input);

                while(m.find()) {

                    if (!matchLimited || matchList.size() < limit - 1) {

                        if (index == 0 && index == m.start() && m.start() == m.end()) {

                            continue;

                        }

                        String match = input.subSequence(index, m.start()).toString();

                        matchList.add(match);

                        index = m.end();

                    } else if (matchList.size() == limit - 1) { // last one

                        String match = input.subSequence(index, input.length()).toString();

                        matchList.add(match);

                        index = m.end();

                    }

                }

                // 如果沒有匹配的,直接返回該字符串

                if (index == 0)

                    return new String[] {input.toString()};

                // 添加最后一個子序列

                if (!matchLimited || matchList.size() < limit)

                    matchList.add(input.subSequence(index, input.length()).toString());

                // 截取后面的空字符

                int resultSize = matchList.size();

                if (limit == 0)

                    while (resultSize > 0 && matchList.get(resultSize-1).equals(""))

                        resultSize--;

                String[] result = new String[resultSize];

                // 集合截取

                return matchList.subList(0, resultSize).toArray(result);

            }

        正則表達式的常用方法:

        Pattern.compile(String regex): 將給定的正則表達式編譯到模式中;

        Pattern.split(CharSequence input): 按照此模式拆分給定的輸入序列;

        Pattern.matcher(CharSequence input): 創建給定輸入與此模式匹配的匹配器;

        Matcher.find(): 查找與該模式匹配的輸入序列的下一個子序列 ;

        Matcher.start(): 返回第一個匹配字符的索引;

        Matcher.end(): 返回最后匹配字符之后的偏移量。

        注意:若split 后字符串數組的尾部字符串為 "", 則需要舍棄空字符串

        來自 “ ITPUB博客 ” ,鏈接:http://www.ep4tq.com/69946279/viewspace-2661085/,如需轉載,請注明出處,否則將追究法律責任。

        請登錄后發表評論 登錄
        全部評論
        管他誰是誰非,做自己的主宰,我是這條街最亮的崽!

        注冊時間:2019-08-22

        • 博文量
          49
        • 訪問量
          21835
        妹子图每日分享