Java字符串分割函数split源码分析
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方法。
public String[] split(String regex, int limit) {
    /* fastpath if the regex is a
     (1)one-char String and this character is not one of the
        RegEx's meta characters ".$|()[{^?*+\\", or
     (2)two-char String and the first char is the backslash and
        the second is not the ascii digit or ascii letter.
     */
    char ch = 0;
    if (((regex.value.length == 1 &&
         ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
         (regex.length() == 2 &&
          regex.charAt(0) == '\\' &&
          (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
          ((ch-'a')|('z'-ch)) < 0 &&
          ((ch-'A')|('Z'-ch)) < 0)) &&
        (ch < Character.MIN_HIGH_SURROGATE ||
         ch > Character.MAX_LOW_SURROGATE))
    {
        //即将加入list的子串的起始索引
        int off = 0;
        //分隔符下次出现的索引
        int next = 0;
        boolean limited = limit > 0;
        //结果集
        ArrayList<String> list = new ArrayList<>();
        //ch为分隔符
        while ((next = indexOf(ch, off)) != -1) {
            if (!limited || list.size() < limit - 1) {
                list.add(substring(off, next));
                off = next + 1;
            } else {    // last one
                //assert (list.size() == limit - 1);
                list.add(substring(off, value.length));
                off = value.length;
                break;
            }
        }
        // If no match was found, return this
        if (off == 0)
            return new String[]{this};
        // Add remaining segment
        if (!limited || list.size() < limit)
            list.add(substring(off, value.length));
        // Construct result
        int resultSize = list.size();
        if (limit == 0) {
            while (resultSize > 0 && list.get(resultSize - 1).isEmpty()) {
                resultSize--;
            }
        }
        String[] result = new String[resultSize];
        return list.subList(0, resultSize).toArray(result);
    }
    return Pattern.compile(regex).split(this, limit);
}
Pattern.split(CharSequence input, int limit)源码
/**
①、limit > 0 ,则pattern(模式)应用limit - 1 次
②、limit = 0 ,则pattern(模式)应用无限次并且省略末尾的空字串
③、limit < 0 ,则pattern(模式)应用无限次,不省略空字符串
*/
public String[] split(CharSequence input, int limit) {
    //即将加入matchList的子串的起始索引
    int index = 0;
    boolean matchLimited = limit > 0;
    //结果集
    ArrayList<String> matchList = new ArrayList<>();
    Matcher m = matcher(input);
    // Add segments before each match found
    while(m.find()) {
        //当limit>0时将input划分为limit段
        //当!matchLimited为true即limit<=0时划分次数不受限制
        if (!matchLimited || matchList.size() < limit - 1) {
            //如果分隔符为空字符串需要保证结果序列的第一个字符串不为空
            //例如"hello"应该被分割为'h','e','l', 'l', 'o',而不是'',h','e','l', 'l', 'o'
            if (index == 0 && index == m.start() && m.start() == m.end()) {
                continue;
            }
            String match = input.subSequence(index, m.start()).toString();
            matchList.add(match);
            index = m.end();
        } else if (matchList.size() == limit - 1) { // 不用继续分割,剩余所有字符作为最后一个子串
            String match = input.subSequence(index,
                                             input.length()).toString();
            matchList.add(match);
            index = m.end();
        }
    }
    // 没有子串匹配,返回原字符串
    if (index == 0)
        return new String[] {input.toString()};
    // 剩余所有字符作为最后一个子串
    if (!matchLimited || matchList.size() < limit)
        matchList.add(input.subSequence(index, input.length()).toString());
    int resultSize = matchList.size();
    //删除尾部所有空子串
    if (limit == 0)
        while (resultSize > 0 && matchList.get(resultSize-1).equals(""))
            resultSize--;
    String[] result = new String[resultSize];
    return matchList.subList(0, resultSize).toArray(result);
}
												
											Java字符串分割函数split源码分析的更多相关文章
- JavaScript中字符串分割函数split用法实例
		
这篇文章主要介绍了JavaScript中字符串分割函数split用法,实例分析了javascript中split函数操作字符串的技巧,非常具有实用价值,需要的朋友可以参考下 本文实例讲述了JavaSc ...
 - java多线程系列(九)---ArrayBlockingQueue源码分析
		
java多线程系列(九)---ArrayBlockingQueue源码分析 目录 认识cpu.核心与线程 java多线程系列(一)之java多线程技能 java多线程系列(二)之对象变量的并发访问 j ...
 - Java集合系列[4]----LinkedHashMap源码分析
		
这篇文章我们开始分析LinkedHashMap的源码,LinkedHashMap继承了HashMap,也就是说LinkedHashMap是在HashMap的基础上扩展而来的,因此在看LinkedHas ...
 - Java并发系列[2]----AbstractQueuedSynchronizer源码分析之独占模式
		
在上一篇<Java并发系列[1]----AbstractQueuedSynchronizer源码分析之概要分析>中我们介绍了AbstractQueuedSynchronizer基本的一些概 ...
 - Java并发系列[3]----AbstractQueuedSynchronizer源码分析之共享模式
		
通过上一篇的分析,我们知道了独占模式获取锁有三种方式,分别是不响应线程中断获取,响应线程中断获取,设置超时时间获取.在共享模式下获取锁的方式也是这三种,而且基本上都是大同小异,我们搞清楚了一种就能很快 ...
 - Java并发系列[5]----ReentrantLock源码分析
		
在Java5.0之前,协调对共享对象的访问可以使用的机制只有synchronized和volatile.我们知道synchronized关键字实现了内置锁,而volatile关键字保证了多线程的内存可 ...
 - java集合系列之LinkedList源码分析
		
java集合系列之LinkedList源码分析 LinkedList数据结构简介 LinkedList底层是通过双端双向链表实现的,其基本数据结构如下,每一个节点类为Node对象,每个Node节点包含 ...
 - java集合系列之ArrayList源码分析
		
java集合系列之ArrayList源码分析(基于jdk1.8) ArrayList简介 ArrayList时List接口的一个非常重要的实现子类,它的底层是通过动态数组实现的,因此它具备查询速度快, ...
 - JAVA设计模式-动态代理(Proxy)源码分析
		
在文章:JAVA设计模式-动态代理(Proxy)示例及说明中,为动态代理设计模式举了一个小小的例子,那么这篇文章就来分析一下源码的实现. 一,Proxy.newProxyInstance方法 @Cal ...
 
随机推荐
- Java程序中使用Spire Jar包报java.lang.NoSuchMethodError类型错误的解决方法
			
Jar包功能概述 使用Spire系列的Jar包可以操作Word.Excel.PPT.PDF.Barcode等格式的文件,分别对应使用的jar包是Spire.Doc for Java.Spire.XLS ...
 - JDK1.8源码阅读笔记(2) AtomicInteger  AtomicLong    AtomicBoolean原子类
			
JDK1.8源码阅读笔记(2) AtomicInteger AtomicLong AtomicBoolean原子类 Unsafe Java中无法直接操作一块内存区域,不能像C++中那样可以自己申请内存 ...
 - Redis的配置文件
 - jQuery扩展方法 (插件机制)
			
jQuery.extend(object) 扩展jQuery对象本身. 用来在jQuery命名空间上增加新函数. 在jQuery命名空间上增加两个函数: <script> jQuery.e ...
 - TypeScript 中装饰器的理解?应用场景?
			
一.是什么 装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上 是一种在不改变原类和使用继承的情况下,动态地扩展对象功能 同样的,本质也不是什么高大上的结构,就是一个普通的 ...
 - AWVS13批量添加目标脚本
			
# -*-coding:utf-8-*- # @Author:malphite.tang import json import requests from queue import Queue req ...
 - (5)java Spring Cloud+Spring boot+mybatis企业快速开发架构之SpringCloud-Spring Boot简介
			
Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目的是简化新 Spring 应用的初始搭建以及开发过程.该框架使用了特定的方式进行配置,从而使开发人员不再需要定义样板化的配置 ...
 - chrome 的 options 参数
			
在使用selenium浏览器渲染技术,爬取网站信息时,默认情况下就是一个普通的纯净的chrome浏览器,而我们平时在使用浏览器时,经常就添加一些插件,扩展,代理之类的应用.相对应的,当我们用chrom ...
 - CF183D-T-shirtx【dp,贪心】
			
正题 题目链接:https://www.luogu.com.cn/problem/CF183D 题目大意 \(n\)个人,\(m\)种衣服,给出每个人喜欢某件衣服的概率,你可以选择\(n\)件衣服带过 ...
 - P7324-[WC2021]表达式求值【dp】
			
正题 题目链接:https://www.luogu.com.cn/problem/P7324 题目大意 给一个只包含\(m\)个值的表达式,\(<\)表前后取最小值,\(>\)表前后取最大 ...