手写String的split()方法以及源码分析

手写String的split()方法,String的split()方法分三种情况:

  1. regex只有一位,且不为列出的特殊字符;
  2. regex有两位,第一位位转义字符且第二位不是数字和字母;
  3. 最后一种情况就是正则表达式去拆分字符串。
package com.dalingjia.algorithm.string;

import com.google.common.collect.Lists;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 手动实现java的split()方法
 */
public class SpiltUtil {

    private static final String contant = ".$|()[{^?*+\\";

    public static String[] splitMethod(String string, String regex){
        char ch = 0;
        int off = 0;
        int next = 0;
        ArrayList<String> list = Lists.newArrayList();
        if(regex.length() == 1 && contant.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)
        {
            while ((next = string.indexOf(ch,off)) > 0){
                list.add(string.substring(off, next));
                off = next + 1;
            }
            if(off == 0){
                return new String[]{string};
            }
            list.add(string.substring(off, string.length()));
            return interceptEmpty(list);
        }
        return regexSplit(string, regex);
    }

    private static String[] regexSplit(String string, String regex) {
        int off = 0;
        //将给定的正则表达式编译到模式中
        Pattern pattern = Pattern.compile(regex);
        //创建给定输入与此模式匹配的匹配器
        Matcher m = pattern.matcher(string);
        List<String> list = Lists.newArrayList();
        while (m.find()){
            //m.start(): 返回第一个匹配字符的索引
            list.add(string.substring(off, m.start()));
            //m.end(): 返回最后匹配字符之后的偏移量
            off = m.end();
        }
        if(off == 0){
            return new String[]{string};
        }
        list.add(string.substring(off, string.length()));
        return interceptEmpty(list);
    }

    //截取空字符串
    private static String[] interceptEmpty(List<String> list){
        //截取空的字符串
        int resultSize = list.size();
        while (resultSize>0 && list.get(resultSize-1).length() == 0){
            resultSize--;
        }
        String[] strings = new String[resultSize];
        return list.subList(0, resultSize).toArray(strings);
    }

    //测试方法
    @Test
    public void test() {
        //测试regex只有一位,且不为列出的特殊字符
        String s1 = "gg,tge,hbfs,ijkd,,,";
        String[] strings1 = splitMethod(s1, ",");
        for (int i = 0; i < strings1.length; i++) {
            System.out.println(strings1[i]);
        }

        //测试regex有两位,第一位位转义字符且第二位不是数字和字母
        String s2 = "bb\'dn\'ags\'kl\'\'";
        String[] strings2 = splitMethod(s2,"\\'");
        for (int i = 0; i < strings2.length; i++) {
            System.out.println(strings2[i]);
        }

        //测试正则表达式
        String ss = "ac32dge533grhr139ljs343";
        String[] strings = splitMethod(ss,"[\\d]+");
        for (int i = 0; i < strings.length; i++) {
            System.out.println(strings[i]);
        }
    }
}

String的split()方法源码如下:

public String[] split(String regex, int limit) {
        char ch = 0;
		if (
                (   //如果regex只有一位,且不为列出的特殊字符
                    (regex.length() == 1 && ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1)
                            ||
                    //如果regex有2位,第一位为转义字符,且第二位不是数字或字母
                    /**
                     * “||”:   如果左边计算后的操作数为true,右边则不再执行,返回true;
                     *
                     * “|”:前后两个操作数都会进行计算。也就是说:“|”不存在短路。
                     */
                    (regex.length() == 2 && regex.charAt(0) == '\\' && ( ((ch = regex.charAt(1))-'0')|('9'-ch) ) < 0 && ((ch-'a')|('z'-ch)) < 0 && ((ch-'A')|('Z'-ch)) < 0)
                )
                        &&
                /**
                 *  UTF-16 编码中的 Unicode 高代理项代码单元的最小值, '\uD800'
                 *  UTF-16 编码中的 Unicode 低代理项代码单元的最大值, '\uDFFF'
                 */
                (ch < Character.MIN_HIGH_SURROGATE || ch > Character.MAX_LOW_SURROGATE)
            ){
            int off = 0;
            int next = 0;
            boolean limited = limit > 0;
            ArrayList<String> list = new ArrayList<>();
            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 (off == 0)
                return new String[]{this};

            // 添加最后一个子序列
            if (!limited || list.size() < limit)
                list.add(substring(off, value.length));

            //截取后面的空字符串
            int resultSize = list.size();
            if (limit == 0) {
                while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
                    resultSize--;
                }
            }
            String[] result = new String[resultSize];
            return list.subList(0, resultSize).toArray(result);
        }
        //第三种情况,利用正则表达式去split字符串
        return Pattern.compile(regex).split(this, limit);
}        

String的split()方法最后一行调用的Pattern的split()方法,二则源码大同小异。
源码如下:

public String[] split(CharSequence input, int limit) {
        int index = 0;
        boolean matchLimited = limit > 0;
        ArrayList<String> matchList = new ArrayList<>();
        Matcher m = matcher(input);
        while(m.find()) {
            if (!matchLimited || matchList.size() < limit - 1) {
                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) { // last one
                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);
    }

正则表达式的常用方法:

  1. Pattern.compile(String regex): 将给定的正则表达式编译到模式中;
  2. Pattern.split(CharSequence input):按照此模式拆分给定的输入序列;
  3. Pattern.matcher(CharSequence input): 创建给定输入与此模式匹配的匹配器;
  4. Matcher.find(): 查找与该模式匹配的输入序列的下一个子序列;
  5. Matcher.start(): 返回第一个匹配字符的索引;
  6. Matcher.end(): 返回最后匹配字符之后的偏移量。

注意:若split后字符串数组的尾部字符串为"",则需要舍弃空字符串

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值