单模式匹配

0x00 引言

文本处理作为计算机基本功能之一,在计算机中是和计算处于同样重要的地位。字符串匹配是文本处理中最基本的功能,也是大家最常使用的功能。关于字符串匹配输入部分只有两个基本成分:原字符串和模式,首次匹配成功的首字母次出现的位置就是输出。下面将介绍一些字符串匹配算法,并给出 Python 实现。简单的字符匹配为什么会存在不同的算法?其实这些算法的主要区别是在匹配过程中移位的策略不同。一花一世界。

0x01 问题描述

Input:原字符串,模式
Output:首次匹配成功的首字母的位置

0x02 Brute Force

该方法就是暴力破解,搞过安全的会遇到各种暴力破解。


class StringSinglePattern(object):
    def __init__(self, base_str, p):
        self.base_str = base_str              # 原字符串
        self.p = p                            # 模式(pattern)
        self.p_len = len(p)
        self.base_str_len = len(base_str)
        self.pi = [0 for i in range(self.p_len)]

    def set_pattern(self, p):
        self.p = p
        self.p_len = len(p)

    def set_base_str(self, base_str):
        self.base_str = base_str
        self.base_str_len = len(base_str)

    '''Brute Force'''

    def brute_force(self):
        p = 0
        b = 0
        if self.p_len > self.base_str_len:
            return 0
        while b <= self.base_str_len:        # can't use for
            if self.base_str[b] == self.p[p]:
                b += 1
                p += 1
            else:
                b = b - p + 1
                p = 0
            if p == self.p_len:
                return b - p
        return 0

0x03 KMP

该算法中的 K 是计算机中的一位大牛,感觉计算机界有“四大天王”你应该认识:Knuth,Dijkstra,Church,Turing。

KMP 算法相对与 Brute Force 来说不是移动一位。
前缀函数


class StringSinglePattern(object):
    def __init__(self, base_str, p):
        self.base_str = base_str              # 原字符串
        self.p = p                            # 模式(pattern)
        self.p_len = len(p)
        self.base_str_len = len(base_str)
        self.pi = [0 for i in range(self.p_len)]

    def set_pattern(self, p):
        self.p = p
        self.p_len = len(p)

    def set_base_str(self, base_str):
        self.base_str = base_str
        self.base_str_len = len(base_str)

    def __kmp_partial_match_table__(self):
        k = 0
        q = 1
        while q < self.p_len:
            while (k > 0) and (self.p[k] != self.p[q]):
                k = self.pi[k - 1]
            if self.p[k] == self.p[q]:
                k = k + 1
            self.pi[q] = k
            q = q + 1
        return 0

    def kmp(self):
        self.__kmp_partial_match_table__()
        print(self.pi)                # next table
        pi_len = len(self.pi)
        k = 0
        for q in range(self.base_str_len):
            while (k > 0) and (self.p[k] != self.base_str[q]):
                k = self.pi[k - 1]
            if self.p[k] == self.base_str[q]:
               k = k + 1
            if k == pi_len:
                return q - pi_len + 1
        return 0

0x04 Boyer Moore

BM 算法相对 KMP 来说移动了更多的位置。

坏字符移动规则:

好后缀移动规则:

坏字符,好后缀,两种移位中的最大值,从右到左,


class StringSinglePattern(object):
    def __init__(self, base_str, p):
        self.base_str = base_str              # 原字符串
        self.p = p                            # 模式(pattern)
        self.p_len = len(p)
        self.base_str_len = len(base_str)
        self.pi = [0 for i in range(self.p_len)]

    def set_pattern(self, p):
        self.p = p
        self.p_len = len(p)

    def set_base_str(self, base_str):
        self.base_str = base_str
        self.base_str_len = len(base_str)

    def __calc_match__(self, num):
        k = num
        j = 0
        while k >= 0:
            if self.p[-k] == self.p[j]:
                k = k - 1
                j = j + 1
                if k <= 0:
                    self.pi[num - 1] = num
                    return 0
            else:
                if num == 1:
                    return 0
                self.pi[num - 1] = self.pi[num - 2]
                return 0

    def __init_good_table__(self):
        i = 1
        while i <= self.p_len:
            self.__calc_match__(i)
            i = i + 1
        print(self.pi)
        return 0

    def __check_bad_table__(self, tmp_base_str):
        i = 1
        while self.p_len - i >= 0:
            if self.p[-i] == tmp_base_str:
                return i
            else:
                i = i + 1
        return self.p_len + 1

    def __check_good_table__(self, num):
        if not num:
            return self.p_len
        else:
            return self.pi[num]

    def bm(self):
        self.__init_good_table__()
        tmp_len = self.p_len
        i = 1
        while tmp_len <= len(self.base_str):
            if self.p[-i] == self.base_str[tmp_len - i]:
                i = i + 1
                if i > self.p_len:
                    return tmp_len - self.p_len
            else:
                tmp_bad = self.__check_bad_table__(self.base_str[tmp_len - i]) - i
                tmp_good = self.p_len - self.__check_good_table__(i - 1)
                tmp_len = tmp_len + max(tmp_bad, tmp_good)
                print(tmp_bad, tmp_good, tmp_len)
                i = 1
        return 0

0x05 Sunday

一次性能验证的串越长,算法的效率越高,Sunday 算法的跨度比BM算法更大,直接从模式串最后一位K开始验证。


class StringSinglePattern(object):
    def __init__(self, base_str, p):
        self.base_str = base_str              # 原字符串
        self.p = p                            # 模式(pattern)
        self.p_len = len(p)
        self.base_str_len = len(base_str)
        self.pi = [0 for i in range(self.p_len)]

    def set_pattern(self, p):
        self.p = p
        self.p_len = len(p)

    def set_base_str(self, base_str):
        self.base_str = base_str
        self.base_str_len = len(base_str)

    def __check_bad_shift__(self, p):
        i = 0
        while i < self.p_len:
            if self.p[i] == p:
                return i
            else:
                i = i + 1
        return -1

    def sunday(self):
        tmp_len = 0
        tmp_hop = self.p_len
        i = 0
        while tmp_hop <= len(self.base_str):
            if self.p[i] == self.base_str[tmp_len + i]:
                i = i + 1
                if i == self.p_len:
                    return tmp_len
            else:
                tmp_len = tmp_len + self.p_len - self.__check_bad_shift__(self.base_str[tmp_hop])
                tmp_hop = tmp_len + self.p_len
                i = 0
        return 0

0x06 Robin-Karp

Hash怎么可以在这种匹配场合不出现勒?

Waitting

0x07 Bitap

Waitting

0x08 图

stringsinglepattern.jpg

0x09 End

学过很多,却一直没有试着去记录那些轨迹,现在准备找工作了,花点时间记录一点点吧。

看到字符串匹配算法,我就想到很多字符串处理工具:grep,sed,awk,ag,pt,Search Everything。

学会这几个小程序有很大的作用,所谓一花一世界。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容

  •   在文本处理中,关键字匹配是一个十分常用且重要的功能。关键字称为模式串,在文本T中寻找模式串P出现的所有出现的位...
    老羊_肖恩阅读 4,477评论 1 4
  • 参考文章 知乎:如何更好的理解和掌握 KMP 算法?从头到尾彻底理解KMPKMP 算法(1):如何理解 KMP(原...
    Mjolnir1107阅读 974评论 0 0
  • 字符串匹配算法之Sunday算法 背景 我们第一次接触字符串匹配,想到的肯定是直接用2个循环来遍历,这样代码虽然简...
    houskii阅读 9,850评论 10 25
  • 串匹配算法也称作模式匹配算法,就是在目标字符串中查找子字符串,常用于文本搜索、入侵检测等领域,将目标字符串定义为T...
    效宇笑语阅读 1,402评论 0 1
  • 是风移动了路标 错过了你等待的路口 我从你面前一晃而过 目光拉着你的影子一路奔走 虽不明白你受伤的心境 清楚看到你...
    曹天成阅读 419评论 1 10