使用KMP算法实现对于指定两个字符之间的字符串分割方法

问题发现

当我在使用正则表达式解决重复匹配字符串时发现,当开头和结尾是同一个字符时且结尾的字符又作为开头,正则表达式无法使用(或许有办法使用,只是我不知道,希望了解的人可以补充),但是传统的字符串匹配方法又无法快速地处理较大的文本,所以我想到了KMP算法,或许可以利用其来解决这个特定的问题,众所周知,KMP算法的效率十分的好,相较于传统的字符串匹配可以更加的快速来匹配子串。

普通KMP算法

import java.util.ArrayList;

public class UsingKMPAlgorithmSpiltString {

    public static void main(String[] args) {
    	//待分割的文本
        String text = "【分割符号】劳力士【分割符号】浪琴【分割符号】欧米茄【分割符号】宝珀【分割符号】百达翡丽" ;
        //分割符号字符串
        String pattern = "【分割符号】";
        UsingKMPAlgorithmSpiltString kmp = new UsingKMPAlgorithmSpiltString();
        ArrayList<Integer> matchIndices = kmp.KMPSearch(text, pattern);

        for (int i = 0; i < matchIndices.size(); i++) {
            if (i + 1 < matchIndices.size()) {
                System.out.println(text.substring(matchIndices.get(i), matchIndices.get(i + 1)));
            } else {
                System.out.println(text.substring(matchIndices.get(i)));
            }
        }
    }

    // 计算部分匹配表(Partial Match Table)
    private int[] computeLPSArray(String pattern) {
        int[] lps = new int[pattern.length()];
        int len = 0; // 长度为已匹配的前缀和后缀的长度
        int i = 1; // lps[0]总是0,所以从1开始

        while (i < pattern.length()) {
            if (pattern.charAt(i) == pattern.charAt(len)) {
                len++;
                lps[i] = len;
                i++;
            } else {
                if (len != 0) {
                    len = lps[len - 1]; // 不匹配时减少len
                } else {
                    lps[i] = 0; // 如果没有匹配到前缀,lps[i]为0
                    i++;
                }
            }
        }
        return lps;
    }

    // KMP 算法实现
    public ArrayList<Integer> KMPSearch(String text, String pattern) {
        ArrayList<Integer> matchIndices = new ArrayList<>();
        int textLength = text.length();
        int patternLength = pattern.length();

        int[] lps = computeLPSArray(pattern);
        int i = 0; // text 中的索引
        int j = 0; // pattern 中的索引

        while (i < textLength) {
            if (pattern.charAt(j) == text.charAt(i)) {
                i++;
                j++;
            }

            if (j == patternLength) {
                matchIndices.add(i - j);
                j = lps[j - 1];
            } else if (i < textLength && pattern.charAt(j) != text.charAt(i)) {
                if (j != 0) {
                    j = lps[j - 1];
                } else {
                    i++;
                }
            }
        }
        return matchIndices;
    }
}

输出结果:

【分割符号】劳力士
【分割符号】浪琴
【分割符号】欧米茄
【分割符号】宝珀
【分割符号】百达翡丽

多模式KMP算法

使用两个进行分割,只要分隔符属于这两个中的其中一个就可以实现分割

import java.util.ArrayList;
import java.util.List;

public class MultimodalKMPAlgorithmSplitString {
    public static void main(String[] args) {
        String text = "离人世,有分也须相遇。约十洲三岛,骖鸾跨鹤,大家同去。 |陈维崧《湖海楼词〖DK〗·凄凉犯〖DK〗·哭云间友人金蓬山》(《清名家词》二〖JP〗172〖JP5〗):玉京伴侣,似人间,也愁离索。促返蓬山,果然去,骖鸾跨鹤。\uE005" +
                "又作〖HTH〗〖BF〗[〖BFB〗骖鸾驭凤〖BF〗]〖BFB〗〖HT〗。武则天《升仙太子碑序》(《全唐文》九八):骖鸾驭凤,升八景而戏仙庭;驾月乘云,驱百灵而朝上帝。\uE003" +
                "又作〖HTH〗〖BF〗[〖BFB〗骖虬驭鹤〖BF〗]〖BFB〗〖HT〗,虬〖WTXT〗〖JP〗(qiú)〖JP5〗〖WT〗:有角的小龙;龙。杜光庭《罗天醮岳渎词》(《全唐文》九三八):仙坛灵化,皆骖虬驭鹤之踪。\uE004" +
                "又作〖HTH〗〖BF〗[〖BFB〗鹤驾鸾骖〖BF〗]〖BFB〗〖HT〗。清〖DK〗·褚人穫《坚瓠集〖DK〗·五集〖DK〗·三〖DK〗·神仙太守》:古今何处有神仙,鹤驾鸾骖总浪传。\uE003" +
                "又作〖HTH〗〖BF〗[〖BFB〗驾鹤骖鸾〖BF〗]〖BFB〗〖HT〗。张大直《题莲华西洞二首(其二)》(《宋诗纪事续补》二五):真人隐壁君休问,驾鹤骖鸾自有时。\uE004" +
                "又作〖HTH〗〖BF〗[〖BFB〗控鹤骖鸾〖BF〗]〖BFB〗〖HT〗。王瞻《高盖名山院记》(《全唐文》九○○):是谓控鹤骖鸾之客,以九仙六洞为家;出生离死之人,以大道三界为宅。\uE004";
        getPara(text,"\uE003","\uE004");
    }
    public static void getPara(String text,String pattern1,String pattern2) {

        // 分割符号字符串
        MultimodalKMPAlgorithmSplitString kmp = new MultimodalKMPAlgorithmSplitString();
        ArrayList<Integer> matchIndices = kmp.multiPatternKMPSearch(text, pattern1, pattern2);

        if (matchIndices.size() > 0) {
            System.out.println(text.substring(0, matchIndices.get(0)));
            for (int i = 0; i < matchIndices.size(); i++) {
                if (i + 1 < matchIndices.size()) {
                    System.out.println(text.substring(matchIndices.get(i) + 1, matchIndices.get(i + 1)));
                } else {
                    System.out.println(text.substring(matchIndices.get(i) + 1));
                }
            }
        }
    }

    // 计算部分匹配表(Partial Match Table)
    private int[] computeLPSArray(String pattern) {
        int[] lps = new int[pattern.length()];
        int len = 0; // 长度为已匹配的前缀和后缀的长度
        int i = 1; // lps[0]总是0,所以从1开始

        while (i < pattern.length()) {
            if (pattern.charAt(i) == pattern.charAt(len)) {
                len++;
                lps[i] = len;
                i++;
            } else {
                if (len != 0) {
                    len = lps[len - 1]; // 不匹配时减少len
                } else {
                    lps[i] = 0; // 如果没有匹配到前缀,lps[i]为0
                    i++;
                }
            }
        }
        return lps;
    }

    // 多模式 KMP 算法实现
    public ArrayList<Integer> multiPatternKMPSearch(String text, String pattern1, String pattern2) {
        ArrayList<Integer> matchIndices = new ArrayList<>();
        List<String> patterns = new ArrayList<>();
        patterns.add(pattern1);
        patterns.add(pattern2);

        for (String pattern : patterns) {
            int textLength = text.length();
            int patternLength = pattern.length();

            int[] lps = computeLPSArray(pattern);
            int i = 0; // text 中的索引
            int j = 0; // pattern 中的索引

            while (i < textLength) {
                if (pattern.charAt(j) == text.charAt(i)) {
                    i++;
                    j++;
                }

                if (j == patternLength) {
                    matchIndices.add(i - j);
                    j = lps[j - 1];
                } else if (i < textLength && pattern.charAt(j) != text.charAt(i)) {
                    if (j != 0) {
                        j = lps[j - 1];
                    } else {
                        i++;
                    }
                }
            }
        }

        // 对匹配结果排序
        matchIndices.sort(Integer::compareTo);
        return matchIndices;
    }
}

输出结果:

离人世,有分也须相遇。约十洲三岛,骖鸾跨鹤,大家同去。 |陈维崧《湖海楼词〖DK〗·凄凉犯〖DK〗·哭云间友人金蓬山》(《清名家词》二〖JP〗172〖JP5〗):玉京伴侣,似人间,也愁离索。促返蓬山,果然去,骖鸾跨鹤。又作〖HTH〗〖BF〗[〖BFB〗骖鸾驭凤〖BF〗]〖BFB〗〖HT〗。武则天《升仙太子碑序》(《全唐文》九八):骖鸾驭凤,升八景而戏仙庭;驾月乘云,驱百灵而朝上帝。
又作〖HTH〗〖BF〗[〖BFB〗骖虬驭鹤〖BF〗]〖BFB〗〖HT〗,虬〖WTXT〗〖JP〗(qiú)〖JP5〗〖WT〗:有角的小龙;龙。杜光庭《罗天醮岳渎词》(《全唐文》九三八):仙坛灵化,皆骖虬驭鹤之踪。
又作〖HTH〗〖BF〗[〖BFB〗鹤驾鸾骖〖BF〗]〖BFB〗〖HT〗。清〖DK〗·褚人穫《坚瓠集〖DK〗·五集〖DK〗·三〖DK〗·神仙太守》:古今何处有神仙,鹤驾鸾骖总浪传。
又作〖HTH〗〖BF〗[〖BFB〗驾鹤骖鸾〖BF〗]〖BFB〗〖HT〗。张大直《题莲华西洞二首(其二)》(《宋诗纪事续补》二五):真人隐壁君休问,驾鹤骖鸾自有时。
又作〖HTH〗〖BF〗[〖BFB〗控鹤骖鸾〖BF〗]〖BFB〗〖HT〗。王瞻《高盖名山院记》(《全唐文》九○○):是谓控鹤骖鸾之客,以九仙六洞为家;出生离死之人,以大道三界为宅。
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值