1.Java 字符分割


使用方法

性能比較 

使用方法 

或|,點.,加+,乘*,在字符串中出現時,如果這個字符串需要被split,則split時候,需要在前面加兩個反斜杠。

與&,在split時候,不需要轉義。

一.java split

1. java split簡單用法

         //一般分隔符 " "
         String a="hello world ni hao";
         String[] array1=a.split(" ");
         System.out.println(array1[0]);
         System.out.println(array1.length);

2.字符串末尾分隔符不能識別

1)字符串末尾的分隔符不能被識別

         String a="hello,world,ni,hao,,,,,";
         String[] array1=a.split(",");
         System.out.println(array1[0]);
         System.out.println(array1.length);       
     ====結果====
     hello
     4 

2).最后兩個字符中間有空格

//字符串末尾的分隔符不能被識別
         String a="hello,world,ni,hao,,,, ,";
         String[] array1=a.split(",");
         System.out.println(array1[0]);
         System.out.println(array1.length);    
     ====結果====   
     hello
     8

3).中間的字符中間有空格

      //字符串末尾的分隔符不能被識別
         String a="hello,world,ni,hao,, ,,,";
         String[] array1=a.split(",");
         System.out.println(array1[0]);
         System.out.println(array1.length);
     ====結果====
     hello
     6

請注意此時的split()方法並不會識別末尾的字符,並分割,當要分割的字符串末尾數據為空時,應注意避免使用此方法,

split()方法可以把字符串直接分割為數組此方法有兩個重載。

一是:split(regex),參數為要分隔的字符串或者正則表達式。
二是:ss.split(regex, limit)。此方法可以的第二個參數一般不太常用,

這兩個方法api給的解釋是:limit 參數控制模式應用的次數,因此影響所得數組的長度。
如果該限制 n 大於 0,則模式將被最多應用 n - 1 次,數組的長度將不會大於 n,而且數組的最后一項將包含所有超出最后匹配的定界符的輸入。
如果 n 為非正,那么模式將被應用盡可能多的次數,而且數組可以是任何長度。
如果 n 為 0,那么模式將被應用盡可能多的次數,數組可以是任何長度,並且結尾空字符串將被丟棄。 

4)-1和5等效

     String a="hello,world,ni,hao,";
         //String[] array1=a.split(",",-1);
        String[] array1=a.split(",",5);
         System.out.println(array1[0]);
         System.out.println(array1.length);

    ====結果
    hello
    5
 

3 特殊符號的分割 

      String a="hello|world|ni|hao";
         String[] array1=a.split("|");
         System.out.println(array1[0]);
         System.out.println(array1.length);
h
18

上面中豎線時特殊符號,應用右雙斜杠轉譯后再分割 ,如下:

 String a="hello|world|ni|hao|";
 String[] array1=a.split("\\|",-1);
 System.out.println(array1[0]);
 System.out.println(array1.length);
hello
5

4 自定義split()方法,java中原生的split方法分割較長字符串時是比較低效的,需要自己重寫split()方法,我自己寫的分割方法如下(利用indexof) 

public static String[] newsplit(String strInfo, String strSplit) {
        // 第1步計算數組大小
        int size = 0;
        int index = 0;
        do {
            size++;
            index++;
            index = strInfo.indexOf(strSplit, index);
        } while (index != -1);
        String[] arrRtn = new String[size]; // 返回數組
        // -------------------------------------------------------
        // 第2步給數組賦值
        int startIndex = 0;
        int endIndex = 0;
        for (int i = 0; i < size; i++) {
            endIndex = strInfo.indexOf(strSplit, startIndex);
            if (endIndex == -1) {
                arrRtn[i] = strInfo.substring(startIndex);
            } else {
                arrRtn[i] = strInfo.substring(startIndex, endIndex);
            }
            startIndex = endIndex + 1;
        }
        return arrRtn;
    }

 

且此方法不需要轉譯特殊字符,因為原生split方法同樣識別正則表達式,所以不是識別特殊字符 

二.org.apache.commons.lang3.StringUtils;

當你需要更高效的split方法時,StringUtils.split(str,"") 方法同樣可用,比原生的split高效,該方法來自 apache-common的jar包,我用的是

commons-lang3-3.0.1.jar的包,但要注意StringUtils.split()對於字符串開頭和結尾的分割符不識別,會默認省去,
StringUtils.split(str, separatorChars, max)

max:最多分割的項數,對於字符串開頭和結尾的分割符不識別,會默認省去

當max<=0時無效。當max>0時為最多的分割項數。

 

String string = "hello,world,ni,hao,";
        String[] strings =  StringUtils.split(string, ",",0);
        System.out.println(strings.length);
        for (String string2 : strings) {
            System.out.println(string2);
        }    

 

String string = "hello,world,ni,hao,";
        String[] strings =  StringUtils.split(string, ",",4);
        System.out.println(strings.length);
        for (String string2 : strings) {
            System.out.println(string2);
        }    
4
hello
world
ni
hao,

三 java.util.StringTokenizer;(不需要用轉義字符)

雖然StringTokenizer用起來很方便,但它的功能卻很有限。這個類只是簡單地在輸入字符串中查找分隔符,一旦找到了分隔符就分割字符串。它不會檢查分隔符是否在子串之中這類條件,當輸入字符串中出現兩個連續的分隔符時,它也不會返回""(字符串長度為0)形式的標記。

對於字符串開頭和結尾的分割符不識別,會默認省去(可以不用轉義字符),多個連續分隔符,也不會處理,

例如

String str = "hello|world|ni|hao|||aa|";
        StringTokenizer st = new StringTokenizer(str, "|");
        
        while (st.hasMoreTokens()) {
            System.out.println("=== : "+st.nextToken());            
        }
=== : hello
=== : world
=== : ni
=== : hao
=== : aa

 只有下邊這種標准格式才能被正常解析:

        String str="hello|world|ni|hao";
        StringTokenizer st = new StringTokenizer(str, "|");    
        String[] strs =new String[st.countTokens()];
        
        int count = 0;
        while (st.hasMoreTokens()) {
            strs[count++] =st.nextToken();            
        }
        
        for (String string : strs) {
            System.out.println(string);
        }
        

完美 解決辦法 :

public static final int  MAXRESULT = 11;
    
    public static final String DELIMIT ="|";
    
    // convert line String to Device object
    public static String[] convertStringToDevice(String lineInfo){        

        
        StringTokenizer st = new StringTokenizer(lineInfo, DELIMIT,true);
        String[]  infos = new String[MAXRESULT];
        
        int i = 0;        
        while (st.hasMoreTokens()) {
            String temp = st.nextToken();    
            if(temp == null ||"null".equals(temp)){
                temp = "";
            }
            
            if("|".equals(temp)){
                if(i++>MAXRESULT){
                    throw new  IllegalArgumentException("Input line has too many fields :" + lineInfo );
                }
                continue;
            }
            infos[i] = temp;
        }
         
        return infos;
        
    }

 

StringTokenizer有兩個常用的方法:

 

1.hasMoreElements()。這個方法和hasMoreTokens()方法的用法是一樣的,只是StringTokenizer為了實現Enumeration接口而實現的方法,從StringTokenizer的聲明可以看到:class StringTokenizer implements Enumeration<Object>。

 

2.nextElement()。這個方法和nextToken()方法的用法是一樣的,返回此 StringTokenizer 的下一個標記。

 

StringTokenizer的三個構造方法:

1.StringTokenizer(String str)。默認以” \t\n\r\f”(前有一個空格,引號不是)為分割符。

//源碼:
public StringTokenizer(String str) {
this(str, ” \t\n\r\f”, false);
}
public static void main(String[] args) {
 StringTokenizer st = new StringTokenizer("www ooobj com");
 while(st.hasMoreElements()){
 System.out.println("Token:" + st.nextToken());
 }
 }

2.StringTokenizer(String str, String delim)。指定delim為分割符,看第一個例子。

3.StringTokenizer(String str, String delim, boolean returnDelims)。returnDelims為true的話則delim分割符也被視為標記。

//實例:
public static void main(String[] args) {  
  StringTokenizer st = new StringTokenizer("www.ooobj.com", ".", true);  
  while(st.hasMoreElements()){  
    System.out.println("Token:" + st.nextToken());  
 }  
} 
 //輸出:

Token:www
Token:.
Token:ooobj
Token:.
Token:com

 

四.c3p0 jar 下的 com.mchange.v1.util.StringTokenizerUtils 可以不用轉義字符,內部是對StringTokenizer封裝;

源碼

/*
 * Distributed as part of c3p0 v.0.9.1.2
 *
 * Copyright (C) 2005 Machinery For Change, Inc.
 *
 * Author: Steve Waldman <swaldman@mchange.com>
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 2.1, as 
 * published by the Free Software Foundation.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this software; see the file LICENSE.  If not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 */


package com.mchange.v1.util;

import java.util.StringTokenizer;

public final class StringTokenizerUtils
{
    public static String[] tokenizeToArray(String str, String delim, boolean returntokens)
    {
    StringTokenizer st = new StringTokenizer(str, delim, returntokens);
    String[] strings = new String[st.countTokens()];
    for (int i = 0; st.hasMoreTokens(); ++i)
       strings[i] = st.nextToken();
    return strings;
    }

    public static String[] tokenizeToArray(String str, String delim)
    {return tokenizeToArray(str, delim, false);}

    public static String[] tokenizeToArray(String str)
    {return tokenizeToArray(str, " \t\r\n");}
}

用法

     String str="hello|world|ni|hao|||";
            
        String[] strs =StringTokenizerUtils.tokenizeToArray(str, "|");        
        
        System.out.println(strs.length);
        
        for (String string : strs) {
            System.out.println(string);
        }
4
hello
world
ni
hao
String str="hello|world|ni|hao|||";
            
        String[] strs =StringTokenizerUtils.tokenizeToArray(str, "|",true);        
        
        System.out.println(strs.length);
        
        for (String string : strs) {
            System.out.println(string);
        }    
10
hello
|
world
|
ni
|
hao
|
|
|

 五.java.util.regex.Pattern;特殊符號需要使用轉義字符

    String str="hello|world|ni|hao|||";
            
        Pattern pattern = Pattern.compile("\\|");
        
        String[] string = pattern.split(str);
        
        for (String string2 : string) {
            System.out.println(string2);
        }

六.使用substring

String  str = "hello|world|ni|hao";
        int len = str.lastIndexOf("|");
        int k = 0,count = 0;        
        for (int i = 0; i <= len; i++) {
            if("|".equals(str.substring(i,i+1))){
                
                if(count ==0){
                    System.out.println(str.substring(0,i));
                    
                }else{
                    System.out.println(str.substring(k+1,i));
                    if(i == len){
                        System.out.println(str.substring(len+1,str.length()));
                    }
                }
                k=i;
                count++;
            }
        }
hello
world
ni
hao

 七.通過charAt和substring這兩個方法實現字符串分割

public static String[] splitByCharAt(String str, char regx) {
        //字符串截取的開始位置
        int begin = 0;
        //截取分割得到的字符串
        String splitStr = "";
        ArrayList<String> result = new ArrayList<String>();
        int length = str.length();
        //計數器
        int i = 0;
        for (i = 0; i < length;i++ ) {
            if (str.charAt(i) == regx) {
                splitStr = str.substring(begin, i);
                result.add(splitStr);
                str = str.substring(i + 1, length);
                length = str.length();
                i = 0;
            }
        }
        if (!StringUtil.isBlank(str)) {
            result.add(str);
        }
        String[] strs = new String[result.size()];
        return result.toArray(strs);
    }

 

性能分析

一.subString、split、stringTokenizer三種截取字符串方法的性能比較

改變目標數據長度修改getOriginStr的len參數即可。

5組測試數據結果如下圖:

下面這張圖對比了下,split耗時為substring和StringTokenizer耗時的倍數:

好吧,我又花了點兒時間,做了幾張圖表來分析這3中方式的性能。

首先來一張柱狀圖對比一下這5組數據截取所花費的時間:

從上圖可以看出StringTokenizer的性能實在是太好了(對比另兩種),幾乎在圖表中看不見它的身影。遙遙領先。substring花費的時間始終比split要少,但是耗時也在隨着數據量的增加而增加。

下面3張折線圖可以很明顯看出split、substring、StringTokenizer3中實現隨着數據量增加,耗時的趨勢。

split是變化最大的,也就是數據量越大,截取所需要的時間增長越快。

substring則比split要平穩一點點,但是也在增長。

 使用String的兩個方法—indexOf()和subString(),subString()是采用了時間換取空間技術,因此它的執行效率相對會很快,只要處理好內存溢出問題,但可大膽使用。而indexOf()函數是一個執行速度非常快的方法,

StringTokenizer則是表現最優秀的,基本上平穩,始終保持在5000ns一下。

結論

最終,StringTokenizer在截取字符串中效率最高,不論數據量大小,幾乎持平。substring則要次之,數據量增加耗時也要隨之增加。split則是表現最差勁的。

究其原因,split的實現方式是采用正則表達式實現,所以其性能會比較低。至於正則表達式為何低,還未去驗證。split源碼如下:

public String[] split(String regex, int limit) {
    return Pattern.compile(regex).split(this, limit);
} 

 二.綜合比較

使用jdk的split切分字符串
192  168  20  121  花費時間1086171
使用common的split切分字符串
192  168  20  121  花費時間9583620
使用StringTokenizer的切分字符串
192  168  20  121  花費時間184380
使用jdk的pattern切分字符串
192  168  20  121  花費時間222654
使用jdk的substring切分字符串
192  168  20  121  花費時間157562
雖然每次打印的時間不太相同,但是基本相差不大。

通過以上分析得知使用substring和StringTokenizer的效率相對較高,其它相對較差。

為什么StringTokenizer的性能相對好些呢?通過分析發現

StringTokener.hasMoreElement和String.split(String.split是用正則表達式匹配,所以不使用KMP字符串匹配算法)用的都是按順序遍歷的算法,時間復雜度O(m*n),較高。

不過StringTokener是一邊按順序遍歷,一邊返回每個分組;而Spring.split是全部分組完成,再返回字符串數組。這個區別不大,但是如果我們不需要全部都分組,只需要某個分組的字符串,那么StringTokener性能會好點。

apacheJakatar的StringUtils一樣用了KMP算法(按序查找字符串,時間是O(m+n)),按理說效率應該最高,但是為啥性能會比較差呢,需要進一步研究。不過有一個優點是如果使用一些轉義字符

如“.”、“|”等不需要加"\\",如果使用jdk的split必須加轉義。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM