split用法的坑

来源:互联网 发布:数学分析教材 知乎 编辑:程序博客网 时间:2024/04/30 12:56

转自:http://yinny.iteye.com/blog/1750210

Java代码  收藏代码
  1.   System.out.println(":ab:cd:ef::".split(":").length);//末尾分隔符全部忽略    
  2.   System.out.println(":ab:cd:ef::".split(":",-1).length);//不忽略任何一个分隔符    
  3.   System.out.println(StringUtils.split(":ab:cd:ef::",":").length);//最前面的和末尾的分隔符全部都忽略,apache commons    
  4.   System.out.println(StringUtils.splitPreserveAllTokens(":ab:cd:ef::",":").length);//不忽略任何一个分隔符 apache commons     
  5. 输出:    
  6. 4    
  7. 6    
  8. 3    
  9. 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方法:
 

Java代码  收藏代码
  1. private static String[] splitWorker(String str, char separatorChar, boolean preserveAllTokens)  
  2. {  
  3.         // Performance tuned for 2.0 (JDK1.4)  
  4.   
  5.         if (str == null) {  
  6.             return null;  
  7.         }  
  8.         int len = str.length();  
  9.         if (len == 0) {  
  10.             return ArrayUtils.EMPTY_STRING_ARRAY;  
  11.         }  
  12.         List list = new ArrayList();  
  13.         int i = 0, start = 0;  
  14.         boolean match = false;  
  15.         boolean lastMatch = false;  
  16.         while (i < len) {  
  17.             if (str.charAt(i) == separatorChar) {  
  18.                 if (match || preserveAllTokens) {  
  19.                     list.add(str.substring(start, i));  
  20.                     match = false;  
  21.                     lastMatch = true;  
  22.                 }  
  23.                 start = ++i;  
  24.                 continue;  
  25.             }  
  26.             lastMatch = false;  
  27.             match = true;  
  28.             i++;  
  29.         }  
  30.         if (match || (preserveAllTokens && lastMatch)) {  
  31.             list.add(str.substring(start, i));  
  32.         }  
  33.         return (String[]) list.toArray(new String[list.size()]);  
  34.     }  
是一个核心方法,用于拆分字符串,其中字符c表示分隔符,另外布尔变量b表示c在首尾的不同处理方式。为真,则在首位留一个""的字符串。但是在中间是没有作用的。该方法执行如下操作: 
  如果字符串为null,则返回null。 
  如果字符串为"",则返回""。 
  用i作为指针遍历字符串,match和lastMatch分别表示遇到和最后遇到可分割的内容。 
    如果字符串中第一个就遇到c,则看b的值,如果为真,则会在结果数组中存入一个""。如果没遇到,match置真,lastMatch置假,表示有要分割的内容。 
    一旦遇到c,则在结果数组中输出字符串在i之前的子字符串,并把起始点调整到i之后。且match置假,lastMatch置真。 
  遍历结束,如果match为真(到最后也没有遇到c),或者lastMatch和b同为真(最后一个字符是c),则输出最后的部分(如果是后者,则会输出一个"")。
 


Java代码  收藏代码
  1. private static String[] splitWorker(String str, String separatorChars, int max, boolean preserveAllTokens)  
  2. {  
  3.         // Performance tuned for 2.0 (JDK1.4)  
  4.         // Direct code is quicker than StringTokenizer.  
  5.         // Also, StringTokenizer uses isSpace() not isWhitespace()  
  6.   
  7.         if (str == null) {  
  8.             return null;  
  9.         }  
  10.         int len = str.length();  
  11.         if (len == 0) {  
  12.             return ArrayUtils.EMPTY_STRING_ARRAY;  
  13.         }  
  14.         List list = new ArrayList();  
  15.         int sizePlus1 = 1;  
  16.         int i = 0, start = 0;  
  17.         boolean match = false;  
  18.         boolean lastMatch = false;  
  19.         if (separatorChars == null) {  
  20.             // Null separator means use whitespace  
  21.             while (i < len) {  
  22.                 if (Character.isWhitespace(str.charAt(i))) {  
  23.                     if (match || preserveAllTokens) {  
  24.                         lastMatch = true;  
  25.                         if (sizePlus1++ == max) {  
  26.                             i = len;  
  27.                             lastMatch = false;  
  28.                         }  
  29.                         list.add(str.substring(start, i));  
  30.                         match = false;  
  31.                     }  
  32.                     start = ++i;  
  33.                     continue;  
  34.                 }  
  35.                 lastMatch = false;  
  36.                 match = true;  
  37.                 i++;  
  38.             }  
  39.         } else if (separatorChars.length() == 1) {  
  40.             // Optimise 1 character case  
  41.             char sep = separatorChars.charAt(0);  
  42.             while (i < len) {  
  43.                 if (str.charAt(i) == sep) {  
  44.                     if (match || preserveAllTokens) {  
  45.                         lastMatch = true;  
  46.                         if (sizePlus1++ == max) {  
  47.                             i = len;  
  48.                             lastMatch = false;  
  49.                         }  
  50.                         list.add(str.substring(start, i));  
  51.                         match = false;  
  52.                     }  
  53.                     start = ++i;  
  54.                     continue;  
  55.                 }  
  56.                 lastMatch = false;  
  57.                 match = true;  
  58.                 i++;  
  59.             }  
  60.         } else {  
  61.             // standard case  
  62.             while (i < len) {  
  63.                 if (separatorChars.indexOf(str.charAt(i)) >= 0) {  
  64.                     if (match || preserveAllTokens) {  
  65.                         lastMatch = true;  
  66.                         if (sizePlus1++ == max) {  
  67.                             i = len;  
  68.                             lastMatch = false;  
  69.                         }  
  70.                         list.add(str.substring(start, i));  
  71.                         match = false;  
  72.                     }  
  73.                     start = ++i;  
  74.                     continue;  
  75.                 }  
  76.                 lastMatch = false;  
  77.                 match = true;  
  78.                 i++;  
  79.             }  
  80.         }  
  81.         if (match || (preserveAllTokens && lastMatch)) {  
  82.             list.add(str.substring(start, i));  
  83.         }  
  84.         return (String[]) list.toArray(new String[list.size()]);  
  85.     }  
也是一个核心方法,用于拆分字符串,其与上一个方法的不同之处在于其分隔符用字符串表示一组字符,且增加一个max变量,表示输出的字符串数组的最大长度。另外注意该方法的b如果为真,会在首尾及中间起作用,且如果分隔符字符串长度大于1,则数组中的""会更多(根据分隔符字符的数量)。该方法执行如下操作: 
  如果字符串为null,则返回null。 
  如果字符串为"",则返回""。 
  之后的处理分三种情况,分别是分隔符字符串为null,则默认为" ";分割符字符串长度为1;分割符字符串为普通字符串。这三种处理的不同只是在当前遍历中的字符的判断问题。 
    1.利用Character.isWhitespace方法判断每个字符是否为" "。 
    2.先把字符串转化为一个char,然后就和前一个splitWorker方法类似。 
    3.利用indexOf方法查找当前字符是否在分隔符字符串中,然后就和前一个splitWorker方法类似。 
    需要注意的是,如果输出的数组的数量已经等于max的值,则把指针直接挪到最后,等待下次遍历的时候直接跳出。同时由于lastMatch和match都置为假,最后也不会输出""了。 
   遍历结束,如果match为真(到最后也没有遇到c),或者lastMatch和b同为真(最后一个字符在分隔符字符串中),则输出最后的部分(如果是后者,则会输出一个"")。

0 0
原创粉丝点击