java 字符串split有很多坑,使用时请小心!!
System.out.println(":ab:cd:ef::".split(":").length);//末尾分隔符全部忽略
System.out.println(":ab:cd:ef::".split(":",-1).length);//不忽略任何一个分隔符
System.out.println(StringUtils.split(":ab:cd:ef::",":").length);//最前面的和末尾的分隔符全部都忽略,apache commons
System.out.println(StringUtils.splitPreserveAllTokens(":ab:cd:ef::",":").length);//不忽略任何一个分隔符 apache commons
输出:
4
6
3
6
看了下jdk里String类的public String[] split(String regex,int limit)方法,感觉平时不太会用这方法,以为在用正则表达式来拆分时候,如果匹配到的字符是最后一个字符时,会拆分出两个空字符串,例 如"o"split("o",5) or "o"split("o",-2)时候 结果是"" "" 也就是下图中红框里的内容,所以平时一般都用split(String regex) 方法,其实也就等同于split(String regex,0)方法,把结尾的空字符串丢弃!
String的split方法用到的参数是一个正则式,虽然强大,但是有时候容易出 错。而且string并没有提供简化版本。org.apache.commons.lang.StringUtils提供的split改变了这一状况,开 始使用完整的字符串作为参数,而不是regex。同时,对类似功能的jdk版本的StringTokenizer,在内部方法splitWorker中有 段注释:Direct code is quicker than StringTokenizer.也就是说,这个是更快的一个工具了~~
StringUtils里的split和splitPreserveAllTokens 底层都是调用splitWorker方法实现的
下面分别来理解下两个私有的splitWorker方法:
private static String[] splitWorker(String str, char separatorChar, boolean preserveAllTokens)
{
// Performance tuned for 2.0 (JDK1.4) if (str == null) {
return null;
}
int len = str.length();
if (len == 0) {
return ArrayUtils.EMPTY_STRING_ARRAY;
}
List list = new ArrayList();
int i = 0, start = 0;
boolean match = false;
boolean lastMatch = false;
while (i < len) {
if (str.charAt(i) == separatorChar) {
if (match || preserveAllTokens) {
list.add(str.substring(start, i));
match = false;
lastMatch = true;
}
start = ++i;
continue;
}
lastMatch = false;
match = true;
i++;
}
if (match || (preserveAllTokens && lastMatch)) {
list.add(str.substring(start, i));
}
return (String[]) list.toArray(new String[list.size()]);
}
是一个核心方法,用于拆分字符串,其中字符c表示分隔符,另外布尔变量b表示c在首尾的不同处理方式。为真,则在首位留一个""的字符串。但是在中间是没有作用的。该方法执行如下操作:
如果字符串为null,则返回null。
如果字符串为"",则返回""。
用i作为指针遍历字符串,match和lastMatch分别表示遇到和最后遇到可分割的内容。
如果字符串中第一个就遇到c,则看b的值,如果为真,则会在结果数组中存入一个""。如果没遇到,match置真,lastMatch置假,表示有要分割的内容。
一旦遇到c,则在结果数组中输出字符串在i之前的子字符串,并把起始点调整到i之后。且match置假,lastMatch置真。
遍历结束,如果match为真(到最后也没有遇到c),或者lastMatch和b同为真(最后一个字符是c),则输出最后的部分(如果是后者,则会输出一个"")。
private static String[] splitWorker(String str, String separatorChars, int max, boolean preserveAllTokens)
{
// Performance tuned for 2.0 (JDK1.4)
// Direct code is quicker than StringTokenizer.
// Also, StringTokenizer uses isSpace() not isWhitespace() if (str == null) {
return null;
}
int len = str.length();
if (len == 0) {
return ArrayUtils.EMPTY_STRING_ARRAY;
}
List list = new ArrayList();
int sizePlus1 = 1;
int i = 0, start = 0;
boolean match = false;
boolean lastMatch = false;
if (separatorChars == null) {
// Null separator means use whitespace
while (i < len) {
if (Character.isWhitespace(str.charAt(i))) {
if (match || preserveAllTokens) {
lastMatch = true;
if (sizePlus1++ == max) {
i = len;
lastMatch = false;
}
list.add(str.substring(start, i));
match = false;
}
start = ++i;
continue;
}
lastMatch = false;
match = true;
i++;
}
} else if (separatorChars.length() == 1) {
// Optimise 1 character case
char sep = separatorChars.charAt(0);
while (i < len) {
if (str.charAt(i) == sep) {
if (match || preserveAllTokens) {
lastMatch = true;
if (sizePlus1++ == max) {
i = len;
lastMatch = false;
}
list.add(str.substring(start, i));
match = false;
}
start = ++i;
continue;
}
lastMatch = false;
match = true;
i++;
}
} else {
// standard case
while (i < len) {
if (separatorChars.indexOf(str.charAt(i)) >= 0) {
if (match || preserveAllTokens) {
lastMatch = true;
if (sizePlus1++ == max) {
i = len;
lastMatch = false;
}
list.add(str.substring(start, i));
match = false;
}
start = ++i;
continue;
}
lastMatch = false;
match = true;
i++;
}
}
if (match || (preserveAllTokens && lastMatch)) {
list.add(str.substring(start, i));
}
return (String[]) list.toArray(new String[list.size()]);
}
也是一个核心方法,用于拆分字符串,其与上一个方法的不同之处在于其分隔符用字符串 表示一组字符,且增加一个max变量,表示输出的字符串数组的最大长度。另外注意该方法的b如果为真,会在首尾及中间起作用,且如果分隔符字符串长度大于 1,则数组中的""会更多(根据分隔符字符的数量)。该方法执行如下操作:
如果字符串为null,则返回null。
如果字符串为"",则返回""。
之后的处理分三种情况,分别是分隔符字符串为null,则默认为" ";分割符字符串长度为1;分割符字符串为普通字符串。这三种处理的不同只是在当前遍历中的字符的判断问题。
1.利用Character.isWhitespace方法判断每个字符是否为" "。
2.先把字符串转化为一个char,然后就和前一个splitWorker方法类似。
3.利用indexOf方法查找当前字符是否在分隔符字符串中,然后就和前一个splitWorker方法类似。
需要注意的是,如果输出的数组的数量已经等于max的值,则把指针直接挪到最后,等待下次遍历的时候直接跳出。同时由于lastMatch和match都置为假,最后也不会输出""了。
遍历结束,如果match为真(到最后也没有遇到c),或者lastMatch和b同为真(最后一个字符在分隔符字符串中),则输出最后的部分(如果是后者,则会输出一个"")。
转载 http://yinny.iteye.com/blog/1750210
java 字符串split有很多坑,使用时请小心!!的更多相关文章
- Java 字符串Split方法的一个坑
java字符串的split,只传一个参数,后面空白的字符串会被忽略: public static void main(String[] args) { String str = "ab|c| ...
- Java字符串split函数的注意事项
Java字符串的split方法可以分割字符串,但和其他语言不太一样,split方法的参数不是单个字符,而是正则表达式,如果输入了竖线(|)这样的字符作为分割字符串,会出现意想不到的结果, 如, Str ...
- Java字符串split分割星号*等特殊字符问题(转)
Java的split()方法分割字符串比较常用(见[Java]字符串以某特殊字符分割处理 ),但在有的时候,会遇到星号*等正则表达式中的特殊字符而无法分割的问题. 比如某需求,用户输入产品规格:厚*宽 ...
- 【java】Split函数踩坑记
先看一段代码: String line = "openssh|7.1"; String[] pkg = line.split("|"); System.out. ...
- Sql2008R2的一个补丁BUG-大家使用时请注意
我们都知道Sqlserver为了提高并发,允许乐观隔离级别(读提交快照,快照)以便读与写之间不阻塞.这里有一个在Sqlserver2008R2 SP2 的热补丁(CU11)下RCSI(读提交快照)隔离 ...
- Java和Javac的使用时总提示找不到类模块的解决方案
1.场景: 争对网上的很多文章中javac编译与java运行的文章,有很多不明确的地方,使得在合适时发现很多坑.这里给大家作下简介. 2.Javac的使用注意: javac -d ./ ./Insta ...
- java关于split分割字符串,空的字符串不能得到的问题
java关于split分割字符串,空的字符串不能得到的问题 class T { public static void main(String args[]) { String num[] = ne ...
- Java 中无返回值的方法在使用时应该注意的问题
Java 中的方法是形态多样的.无返回值的方法在使用时应该规避哪些问题呢? 一.不可以打印调用或是赋值调用,只能是单独调用(非常重要): 二.返回值没有,不代表参数就没有: 三.不能return一个具 ...
- Java字符串分割函数split源码分析
spilt方法作用 以所有匹配regex的子串为分隔符,将input划分为多个子串. 例如: The input "boo:and:foo", for example, yield ...
随机推荐
- iOS frame从导航栏下面开始
iOS7.0 之后,页面布局默认延伸到了手机界面的边缘;导航栏背景成透明颜色. 解决fram从导航栏下面开始方法: 第一种: 将导航栏改成不透明即可 if( ([[[UIDevice currentD ...
- PowerDesigner 15.2入门学习 二
PowerDesigner中如何生成主键和自增列 1.SQL Server版本: 第一步,首先要建立与数据库的连接,方法较多,这里举个例子: http://www.cnblogs.com/netsql ...
- 关于c++风格 code style
Header files should be self-contained. All header files should have #define guards to prevent multip ...
- JS写的CRC16校验算法(查表法)
var CRC = {}; CRC._auchCRCHi = [ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0 ...
- URAL 2080 莫队
题意 有m种卡 给出卡的使用序列 要求每次从卡堆的顶部抽一张出来 刚好符合序列 输出初始 卡堆的排序 再输出每次抽出卡用后 卡插回卡堆的时候 这张卡上面有几张卡 初始排序很容易就可以搞出来 但是需要注 ...
- ThinkPHP 3.2.3 Widget 扩展的使用
ThinkPHP3.2.3 手册中 Widget 扩展的地址是: http://www.kancloud.cn/manual/thinkphp/1862 Widget 扩展一般用于页面组件的扩展,和自 ...
- Box2D淌坑日记: 关节(Joint)和旋转关节(b2RevoluteJoint)
关节在Box2D的对象组织结构中,与b2Body(刚体)并列.因此两种对象都是由b2World创建并直接管理. 然而Joint有依赖于b2Body的地方,就是它的销毁:当关节所涉及到的刚体被销毁,关节 ...
- ios开发xcode中设置代码块
在开发中有很多重复的代码,很多开发者把常用的代码做成代码块提高开发效率. 在xcode里选中代码块的时候总是很不容易,点击选中的代码(文字),不要移动和松开鼠标左键,当竖线变成像拉长了的x(我也不知道 ...
- LeetCode Palindrome Permutation II
原题链接在这里:https://leetcode.com/problems/palindrome-permutation-ii/ 题目: Given a string s, return all th ...
- 白话学习MVC(八)Action的执行二
一.概述 上篇博文<白话学习MVC(七)Action的执行一>介绍了ASP.NET MVC中Action的执行的简要流程,并且对TempData的运行机制进行了详细的分析,本篇来分析上一篇 ...