spilt方法作用

以所有匹配regex的子串为分隔符,将input划分为多个子串。

例如:

The input "boo:and:foo", for example, yields the following results with these expressions:

Regex Result

:{ "boo", "and", "foo" }

o { "b", "", ":and:f" }

limit参数

①、limit > 0 ,则pattern(模式)应用limit - 1 次

②、limit = 0 ,则pattern(模式)应用无限次并且省略末尾的空子串

③、limit < 0 ,则pattern(模式)应用无限次,不省略空子串

如果没有传limit参数,那么实际上调用的是split(regex,0),即limit=0,此时尽可能地分割并省略尾部的空子串。

String.split(String regex, int limit)源码

参数regex是String类型,但需要按照正则表达式的语法格式去写(例如有的字符在正则表达式里有特殊含义而我们不想它有这特殊含义,那么我们就要对这个字符进行转义)。为什么要按照正则表达式的语法格式去写呢?因为我们实际上需要借助Pattern类的split方法来完成功能。

但如果regex比较简单,杀鸡焉用牛刀,我们就自己实现分割而不用去调用Pattern.split方法。当regex属于特定两种类型之一时是自己去实现分割的:

(1)regex只包含单个字符且不是特殊字符。

(2)regex包含两个字符,第一个字符是正则表达式转义用的反斜杠,即regex是个转义字符,但转义前后只是改变了字符的语义没有改变字符的外形。例如"\\?"直接就表示"?"这个字符,前面加上反斜杠是因为"?"在正则表达式中为特殊字符,我们需要转义(之所以有两个反斜杠是因为反斜杠本身在Java字符串中就有转义功能,所以需要转义一次)。但实际上我们没有交由Pattern.split方法来处理,也就是说我们根本没有涉及到正则表达式匹配,那么这里的转义就没有意义了,那么我们就可以直接取"\\?"的第二个字符"?"作为分隔符。

无论上面两种情况的哪一种,最后实际上都是单个字符作为分隔符的。而对于更复杂的情况,我们去调用Pattern.split方法。

  1. public String[] split(String regex, int limit) {
  2. /* fastpath if the regex is a
  3. (1)one-char String and this character is not one of the
  4. RegEx's meta characters ".$|()[{^?*+\\", or
  5. (2)two-char String and the first char is the backslash and
  6. the second is not the ascii digit or ascii letter.
  7. */
  8. char ch = 0;
  9. if (((regex.value.length == 1 &&
  10. ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
  11. (regex.length() == 2 &&
  12. regex.charAt(0) == '\\' &&
  13. (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
  14. ((ch-'a')|('z'-ch)) < 0 &&
  15. ((ch-'A')|('Z'-ch)) < 0)) &&
  16. (ch < Character.MIN_HIGH_SURROGATE ||
  17. ch > Character.MAX_LOW_SURROGATE))
  18. {
  19. //即将加入list的子串的起始索引
  20. int off = 0;
  21. //分隔符下次出现的索引
  22. int next = 0;
  23. boolean limited = limit > 0;
  24. //结果集
  25. ArrayList<String> list = new ArrayList<>();
  26. //ch为分隔符
  27. while ((next = indexOf(ch, off)) != -1) {
  28. if (!limited || list.size() < limit - 1) {
  29. list.add(substring(off, next));
  30. off = next + 1;
  31. } else { // last one
  32. //assert (list.size() == limit - 1);
  33. list.add(substring(off, value.length));
  34. off = value.length;
  35. break;
  36. }
  37. }
  38. // If no match was found, return this
  39. if (off == 0)
  40. return new String[]{this};
  41. // Add remaining segment
  42. if (!limited || list.size() < limit)
  43. list.add(substring(off, value.length));
  44. // Construct result
  45. int resultSize = list.size();
  46. if (limit == 0) {
  47. while (resultSize > 0 && list.get(resultSize - 1).isEmpty()) {
  48. resultSize--;
  49. }
  50. }
  51. String[] result = new String[resultSize];
  52. return list.subList(0, resultSize).toArray(result);
  53. }
  54. return Pattern.compile(regex).split(this, limit);
  55. }

Pattern.split(CharSequence input, int limit)源码

  1. /**
  2. ①、limit > 0 ,则pattern(模式)应用limit - 1 次
  3. ②、limit = 0 ,则pattern(模式)应用无限次并且省略末尾的空字串
  4. ③、limit < 0 ,则pattern(模式)应用无限次,不省略空字符串
  5. */
  6. public String[] split(CharSequence input, int limit) {
  7. //即将加入matchList的子串的起始索引
  8. int index = 0;
  9. boolean matchLimited = limit > 0;
  10. //结果集
  11. ArrayList<String> matchList = new ArrayList<>();
  12. Matcher m = matcher(input);
  13. // Add segments before each match found
  14. while(m.find()) {
  15. //当limit>0时将input划分为limit段
  16. //当!matchLimited为true即limit<=0时划分次数不受限制
  17. if (!matchLimited || matchList.size() < limit - 1) {
  18. //如果分隔符为空字符串需要保证结果序列的第一个字符串不为空
  19. //例如"hello"应该被分割为'h','e','l', 'l', 'o',而不是'',h','e','l', 'l', 'o'
  20. if (index == 0 && index == m.start() && m.start() == m.end()) {
  21. continue;
  22. }
  23. String match = input.subSequence(index, m.start()).toString();
  24. matchList.add(match);
  25. index = m.end();
  26. } else if (matchList.size() == limit - 1) { // 不用继续分割,剩余所有字符作为最后一个子串
  27. String match = input.subSequence(index,
  28. input.length()).toString();
  29. matchList.add(match);
  30. index = m.end();
  31. }
  32. }
  33. // 没有子串匹配,返回原字符串
  34. if (index == 0)
  35. return new String[] {input.toString()};
  36. // 剩余所有字符作为最后一个子串
  37. if (!matchLimited || matchList.size() < limit)
  38. matchList.add(input.subSequence(index, input.length()).toString());
  39. int resultSize = matchList.size();
  40. //删除尾部所有空子串
  41. if (limit == 0)
  42. while (resultSize > 0 && matchList.get(resultSize-1).equals(""))
  43. resultSize--;
  44. String[] result = new String[resultSize];
  45. return matchList.subList(0, resultSize).toArray(result);
  46. }

Java字符串分割函数split源码分析的更多相关文章

  1. JavaScript中字符串分割函数split用法实例

    这篇文章主要介绍了JavaScript中字符串分割函数split用法,实例分析了javascript中split函数操作字符串的技巧,非常具有实用价值,需要的朋友可以参考下 本文实例讲述了JavaSc ...

  2. java多线程系列(九)---ArrayBlockingQueue源码分析

    java多线程系列(九)---ArrayBlockingQueue源码分析 目录 认识cpu.核心与线程 java多线程系列(一)之java多线程技能 java多线程系列(二)之对象变量的并发访问 j ...

  3. Java集合系列[4]----LinkedHashMap源码分析

    这篇文章我们开始分析LinkedHashMap的源码,LinkedHashMap继承了HashMap,也就是说LinkedHashMap是在HashMap的基础上扩展而来的,因此在看LinkedHas ...

  4. Java并发系列[2]----AbstractQueuedSynchronizer源码分析之独占模式

    在上一篇<Java并发系列[1]----AbstractQueuedSynchronizer源码分析之概要分析>中我们介绍了AbstractQueuedSynchronizer基本的一些概 ...

  5. Java并发系列[3]----AbstractQueuedSynchronizer源码分析之共享模式

    通过上一篇的分析,我们知道了独占模式获取锁有三种方式,分别是不响应线程中断获取,响应线程中断获取,设置超时时间获取.在共享模式下获取锁的方式也是这三种,而且基本上都是大同小异,我们搞清楚了一种就能很快 ...

  6. Java并发系列[5]----ReentrantLock源码分析

    在Java5.0之前,协调对共享对象的访问可以使用的机制只有synchronized和volatile.我们知道synchronized关键字实现了内置锁,而volatile关键字保证了多线程的内存可 ...

  7. java集合系列之LinkedList源码分析

    java集合系列之LinkedList源码分析 LinkedList数据结构简介 LinkedList底层是通过双端双向链表实现的,其基本数据结构如下,每一个节点类为Node对象,每个Node节点包含 ...

  8. java集合系列之ArrayList源码分析

    java集合系列之ArrayList源码分析(基于jdk1.8) ArrayList简介 ArrayList时List接口的一个非常重要的实现子类,它的底层是通过动态数组实现的,因此它具备查询速度快, ...

  9. JAVA设计模式-动态代理(Proxy)源码分析

    在文章:JAVA设计模式-动态代理(Proxy)示例及说明中,为动态代理设计模式举了一个小小的例子,那么这篇文章就来分析一下源码的实现. 一,Proxy.newProxyInstance方法 @Cal ...

随机推荐

  1. Pytest系列(19)- 我们需要掌握的allure特性

    如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html 前言 前面我们介绍了allure的 ...

  2. 使用Java MVC模式设计一个学生管理系统

    最近在做web实验,要求是用jsp+servlet+mysql实现一个学生管理系统,完成对数据库的增删改查. 效果图:   代码: package dao; import java.util.List ...

  3. Spring框架(第二天)

    一. 注入 a)  set i. JDK 1.八种基本类型(+包装类)+String <bean id="User" class="com.dsl.test2.Us ...

  4. 了解PHP-FPM

    在服务器上,当我们查看php进程时,全都是php-fpm进程,大家都知道这个就是php的运行环境,那么,它到底是个什么东西呢? PHP-FPM简介 PHP-FPM,就是PHP的FastCGI管理器,用 ...

  5. mysql5.7当两个字段名类似,查询时会出错

    excepInfo: select id,describe from iwebshop_student_problem where id=256 order by id desc -- You hav ...

  6. symfony2中mysql和mongodb的增删改查总结

    https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/data-retrieval-and-manip ...

  7. JS验证监听输入银行卡号

    $("#AccountNum").keydown(function(e) { if(!isNaN(this.value.replace(/[ ]/g,""))) ...

  8. Jmeter系列(2)- 代理服务器录制脚本

    操作步骤 step-1 添加代理服务器 step-2 添加线程组 step-3 添加录制控制器 HTTP代理服务器配置 - HTTP(S) Test Script Recorder TestPlan ...

  9. 解决navicat 导出excel数字为科学计数法问题

    1.原因分析      用程序导出的csv文件,当字段中有比较长的数字字段存在时,在用excel软件查看csv文件时就会变成科学技术法的表现形式.     其实这个问题跟用什么语言导出csv文件没有关 ...

  10. git pull 时remote: HTTP Basic: Access denied解决方案

    当qian windows用户密码过期更改了密码后,操作git pull 拉取远程仓库代码或git push时报错 如下:remote: HTTP Basic: Access denied  Auth ...