Split()拆分字符串与StringTokenizer拆分字符串

前言

不管用何种编程语言写代码,对字符串的处理都是必不可少的,其中对字符串的拆分在许多场合都频繁用到。
今天介绍Java中两种主流的拆分方法,一是lang包String类的split()方法,另一种则是util包下的StringTokenizer类。


String.split()拆分字符串

1.单参数拆分方法

public String[] split(String regex)
  • 参数: regex-the delimiting regular expression,定界正则表达式

  • 返回: String[],字符串数组,它是根据给定正则表达式的匹配拆分此字符串确定的,如果表达式不匹配输入的任何部分,那么所得数组只具有一个元素,即此字符串。

  • 抛出: PatternSyntaxException - 如果正则表达式的语法无效

  • 特点: 该方法的作用就像是使用给定的表达式和限制参数 0 来调用两参数 split 方法,即是split(String regex,0)。因此,所得数组中不包括结尾空字符串。

拆分示例

拆分字符串"Harry James Potter",以空格进行拆分

package demotest;
public class SplitDemo {
	public static void main(String[] args) {
		String nameStr="Harry James Potter";
		//"\\s"表示空格
		String[] nameStrArray=nameStr.split("\\s");
		//也可以来" "来进行拆分,这种方法要注意中间只能有一个空格,如果有两个空格则不能正常拆分,最后得到的仍是原有字符串
		//String[] nameStrArray=nameStr.split(" ");
		for(String name:nameStrArray){
			System.out.println(name);
		}
	}	
}

拆分结果

Harry
James
Potter

拆分后的字符数组不包含节尾空字符串

用单参数split()方法拆分字符串时会发现有时拆分出来的字符串数组长度好像与预期不一致,这是因为当最后拆分出的那个字符串为空字符时,这个空字符不会加到数组中去。
示例:拆分"Harry#James#Potter###",以"#"号进行拆分,按感觉来说应该会拆分成六段

package demotest;
import java.util.Arrays;
public class SplitDemo {
	public static void main(String[] args) {
		String nameStr="Harry#James#Potter###";
		String[] nameStrArray=nameStr.split("#");
		for(String name:nameStrArray){
			System.out.println(name);
		}
		System.out.println("数组长度为:"+nameStrArray.length);
		System.out.println("数组值为:"+Arrays.toString(nameStrArray));
	}	
}

运行结果如下:

Harry
James
Potter
数组长度为:3
数组值为:[Harry, James, Potter]

从结果来看,实际上拆分出的数组只有三位,##之间与之后的空字符串都不会被加入至这个数组中。

2.双参数拆分方法

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

参数比上面方法多了一个int类型,limit 参数控制模式应用的次数,即拆分的次数,因此影响所得数组的长度。下面n所指为limit参数

  • 如果该限制 n 大于 0,则模式将被最多应用 n - 1 次,数组的长度将不会大于 n,而且数组的最后一项将包含所有超出最后匹配的定界符的输入。

  • 如果 n 为非正,那么模式将被应用尽可能多的次数,而且数组可以是任何长度。

  • 如果 n 为 0,那么模式将被应用尽可能多的次数,数组可以是任何长度,并且结尾空字符串将被丢弃。

limit为正负数时的示例

依旧以"Harry#James#Potter###",以"#"号进行拆分

1.当limit为1时,拆分结果如下,数组长度应不大于1,即小于等于1.

String nameStr="Harry#James#Potter###";
String[] nameStrArray=nameStr.split("#",1);
//结果如下,字符串原样输出了,因为拆分只进行了1-1次,即0次
Harry#James#Potter###
数组长度为:1
数组值为:[Harry#James#Potter###]

2.当limit为4时,拆分了三次,数组长度应不大于4.

String[] nameStrArray=nameStr.split("#",4);
//拆分结果如下,最后一个字符串为"##",说明这两个还没被拆分
Harry
James
Potter
##
数组长度为:4
数组值为:[Harry, James, Potter, ##]

3.当limit为-1时,字符串会被尽可能地被多拆分

String[] nameStrArray=nameStr.split("#",-1);
//拆分结果如下,数组长度为6,其中包含了三个空字符,说明将所有的#都进行了拆分,字符串不再有#存在
Harry
James
Potter



数组长度为:6
数组值为:[Harry, James, Potter, , , ]

4.当limit为-2时,拆分结果与-1时一致,所以当这个limit是负数时,不管传什么值,结果都是一致的。

String[] nameStrArray=nameStr.split("#",-1);
//拆分结果与-1时一致
Harry
James
Potter



数组长度为:6
数组值为:[Harry, James, Potter, , , ]

3.与str.split(regex,limit)结果相同的方法

以下运用字符串匹配的方法与字符串拆分方法返回的结果一致。

Pattern.compile(regex).split(str, n)

StringTokenizer类拆分字符串

拆分原理

StringTokenizer拆分字符串的原理是通过生成StringTokenizer对象,
然后运用对象的属性来处理字符串拆分的。
StringTokenizer类有三个构造函数,分别是一个参数,两个参数,三个参数的构造函数。

public StringTokenizer(String str,String delim,boolean returnDelims)

public StringTokenizer(String str,String delim)

public StringTokenizer(String str)
                       

构造函数为指定字符串构造一个 string tokenizer。delim 参数中的所有字符都是分隔标记的分隔符,即是拆分的标识字符串,以此字符对字符串进行拆分。

  • 如果 returnDelims 标志为 true,则分隔符字符也作为标记返回。每个分隔符都作为一个长度为 1 的字符串返回。如果标志为 false,则跳过分隔符,只是用作标记之间的分隔符。

  • 注意,如果 delim 为 null,则此构造方法不抛出异常。但是,尝试对得到的 StringTokenizer 调用其他方法则可能抛出 NullPointerException。

  • 参数:
    str - 要解析的字符串。
    delim - 分隔符。
    returnDelims - 指示是否将分隔符作为标记返回的标志。

  • 抛出
    NullPointerException - 如果 str 为 null。

  • delim默认值 :当构造函数为一个参数时,tokenizer 使用默认的分隔符集 " \t\n\r\f",即:空白字符、制表符、换行符、回车符和换页符。分隔符字符本身不作为标记。

拆分示例

1.单参数时,delim为默认值

package demotest;
import java.util.StringTokenizer;
public class StringTokenDemo {
	public static void main(String[] args) {
		String nameStr="Harry James Potter";
		//将要拆分的字符传入构造函数中,生成一个token对象
		StringTokenizer strToken=new StringTokenizer(nameStr);
		//当有拆分的子字符串时,输出这个字符串
		while(strToken.hasMoreTokens()){
			System.out.println(strToken.nextToken());
		}
	}
}

运行结果

Harry
James
Potter

2.双参数时,delim为"#",拆分"Harry#James#Potter###"

//构造函数双参数
StringTokenizer strToken=new StringTokenizer(nameStr,"#");
//运行结果
Harry
James
Potter

3.三参数时,returnDelims为true,返回作为分隔符的#号

//构造函数双参数
StringTokenizer strToken=new StringTokenizer(nameStr,"#",true);
//运行结果,#号也作为strToken.nextToken()值被添加进去了。
Harry
#
James
#
Potter
#
#
#

官方推荐使用split进行字符串拆分

从上面两种方法的案例其实可以看出String.split()方法比StringTokenizer类的拆分方法更加简洁和方便后续处理。
split可以匹配正则表达式,而StringTokenizer则不行。且大多数时候拆分得到的子字符串是要进行操作的,而StringTokenizer类操作子字符串是靠遍历进行的,比较繁琐,相比之下运用数组进行下标操作就方便多了,事实上官方也不推荐用StringTokenizer类生成对象的方法来进行字符串的拆分操作了。

2018.12.30更新

评论中两条都是说StringTokenizer类比Split拆分效率更高,在查找相关博客后,觉得自己之前关于上述推荐的说法确实不太严谨,所以将关于效率的字眼删除了。关于两者效率我也无法得出结论,参考该篇博客StringTokenizer和split分隔字符串效率比较。
String.split 和 StringTokenizer的区别

官方文档中确实是不推荐使用StringTokenizer类的,文档链接

StringTokenizer is a legacy class that is retained for compatibility reasons although its use is discouraged in new code. It is recommended that anyone seeking this functionality use the split method of String or the java.util.regex package instead.
谷歌翻译:StringTokenizer是一个遗留类,出于兼容性原因而保留,尽管在新代码中不鼓励使用它。 建议任何寻求此功能的人都使用String的split方法或java.util.regex包。
The following example illustrates how the String.split method can be used to break up a string into its basic tokens:

 String[] result = "this is a test".split("\\s");
 for (int x=0; x

你可能感兴趣的:(JavaSE)