單模式匹配

0x00 引言

文本處理作為計(jì)算機(jī)基本功能之一,在計(jì)算機(jī)中是和計(jì)算處于同樣重要的地位。字符串匹配是文本處理中最基本的功能,也是大家最常使用的功能。關(guān)于字符串匹配輸入部分只有兩個(gè)基本成分:原字符串和模式,首次匹配成功的首字母次出現(xiàn)的位置就是輸出。下面將介紹一些字符串匹配算法,并給出 Python 實(shí)現(xiàn)。簡(jiǎn)單的字符匹配為什么會(huì)存在不同的算法?其實(shí)這些算法的主要區(qū)別是在匹配過(guò)程中移位的策略不同。一花一世界。

0x01 問(wèn)題描述

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

0x02 Brute Force

該方法就是暴力破解,搞過(guò)安全的會(huì)遇到各種暴力破解。


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 是計(jì)算機(jī)中的一位大牛,感覺(jué)計(jì)算機(jī)界有“四大天王”你應(yīng)該認(rèn)識(shí):Knuth,Dijkstra,Church,Turing。

KMP 算法相對(duì)與 Brute Force 來(lái)說(shuō)不是移動(dòng)一位。
前綴函數(shù)


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 算法相對(duì) KMP 來(lái)說(shuō)移動(dòng)了更多的位置。

壞字符移動(dòng)規(guī)則:

好后綴移動(dòng)規(guī)則:

壞字符,好后綴,兩種移位中的最大值,從右到左,


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

一次性能驗(yàn)證的串越長(zhǎng),算法的效率越高,Sunday 算法的跨度比BM算法更大,直接從模式串最后一位K開(kāi)始驗(yàn)證。


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怎么可以在這種匹配場(chǎng)合不出現(xiàn)勒?

Waitting

0x07 Bitap

Waitting

0x08 圖

stringsinglepattern.jpg

0x09 End

學(xué)過(guò)很多,卻一直沒(méi)有試著去記錄那些軌跡,現(xiàn)在準(zhǔn)備找工作了,花點(diǎn)時(shí)間記錄一點(diǎn)點(diǎn)吧。

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

學(xué)會(huì)這幾個(gè)小程序有很大的作用,所謂一花一世界。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • ??在文本處理中,關(guān)鍵字匹配是一個(gè)十分常用且重要的功能。關(guān)鍵字稱(chēng)為模式串,在文本T中尋找模式串P出現(xiàn)的所有出現(xiàn)的位...
    老羊_肖恩閱讀 4,674評(píng)論 1 4
  • 參考文章 知乎:如何更好的理解和掌握 KMP 算法?從頭到尾徹底理解KMPKMP 算法(1):如何理解 KMP(原...
    Mjolnir1107閱讀 1,232評(píng)論 0 0
  • 字符串匹配算法之Sunday算法 背景 我們第一次接觸字符串匹配,想到的肯定是直接用2個(gè)循環(huán)來(lái)遍歷,這樣代碼雖然簡(jiǎn)...
    houskii閱讀 10,169評(píng)論 10 25
  • 串匹配算法也稱(chēng)作模式匹配算法,就是在目標(biāo)字符串中查找子字符串,常用于文本搜索、入侵檢測(cè)等領(lǐng)域,將目標(biāo)字符串定義為T(mén)...
    效宇笑語(yǔ)閱讀 1,543評(píng)論 0 1
  • 是風(fēng)移動(dòng)了路標(biāo) 錯(cuò)過(guò)了你等待的路口 我從你面前一晃而過(guò) 目光拉著你的影子一路奔走 雖不明白你受傷的心境 清楚看到你...
    曹天成閱讀 446評(píng)論 1 10

友情鏈接更多精彩內(nèi)容