字符串的模式匹配算法

合集下载

kmp算法 公式

kmp算法 公式

KMP算法是一种字符串匹配算法,用于在一个主串中查找一个模式串的出现位置。

它的核心思想是利用已经匹配过的部分信息,尽量减少不必要的比较。

KMP算法的公式如下:1. 预处理模式串,得到next数组:-初始化next数组,next[0] = -1,next[1] = 0;-从第2个字符开始,依次计算next[i]的值:-如果模式串的前缀和后缀匹配,即pattern[j] == pattern[i-1],则next[i] = j + 1;-如果模式串的前缀和后缀不匹配,即pattern[j] != pattern[i-1],则需要回溯到前一个可能的匹配位置,即j = next[j],直到找到一个匹配位置或者回溯到起始位置;-如果回溯到起始位置仍然没有找到匹配位置,则next[i] = 0。

2. 在主串中查找模式串:-初始化主串指针i = 0,模式串指针j = 0;-依次比较主串和模式串的字符:-如果主串和模式串的字符匹配,即text[i] == pattern[j],则继续比较下一个字符;-如果主串和模式串的字符不匹配,即text[i] != pattern[j],则需要根据next数组回溯模式串的指针j,即j = next[j],直到找到一个匹配位置或者回溯到起始位置;-如果回溯到起始位置仍然没有找到匹配位置,则主串指针i和模式串指针j都向后移动一位,继续比较下一个字符;-如果模式串指针j移动到模式串的末尾,则表示找到了一个匹配位置,返回匹配位置的起始索引;-如果主串指针i移动到主串的末尾,则表示没有找到匹配位置,返回-1。

KMP算法通过预处理模式串得到next数组,利用next数组的信息在匹配过程中尽量减少不必要的比较,提高了匹配效率。

实现字符串匹配算法,支持正则表达式(JavaScript)

实现字符串匹配算法,支持正则表达式(JavaScript)

实现字符串匹配算法,支持正则表达式(JavaScript)字符串匹配是计算机领域中常见的操作,当我们需要在一个字符串中查找特定的模式时,可以使用字符串匹配算法来实现。

在实际应用中,经常会用到正则表达式来描述匹配的规则。

在JavaScript中,我们可以使用内置的正则表达式对象来实现字符串匹配。

以下将介绍三种常见的字符串匹配算法:暴力法、KMP算法和正则表达式匹配算法。

1.暴力法(Brute Force)暴力法是最简单直接的字符串匹配算法。

它的基本思想是从目标字符串的每一个字符开始,逐个比较目标字符串和模式字符串的字符,如果相等,则继续比较下一个字符,如果不相等,则将目标字符串的指针回溯到上一个位置的下一个字符位置,重新开始比较。

暴力法的实现代码如下:```javascriptfunction bruteForceSearch(text, pattern) { const m = text.length;const n = pattern.length;for (let i = 0; i <= m - n; i++) {let j;for (j = 0; j < n; j++) {if (text[i + j] !== pattern[j]) {break;}}if (j === n) {return i; //匹配成功,返回起始位置}}return -1; //匹配失败}```2. KMP算法(Knuth-Morris-Pratt)KMP算法是一种高效的字符串匹配算法,它利用已经匹配过的信息避免不必要的比较。

基本思想是构建一个部分匹配表(Partial Match Table),通过部分匹配表可以确定在回溯时应该回溯到的位置。

KMP算法的实现代码如下:```javascript//构建部分匹配表function buildPartialMatchTable(pattern) {const table = [0];let prefixIndex = 0;let suffixIndex = 1;while (suffixIndex < pattern.length) {if (pattern[prefixIndex] === pattern[suffixIndex]) { table[suffixIndex] = prefixIndex + 1;prefixIndex++;suffixIndex++;} else if (prefixIndex === 0) {table[suffixIndex] = 0;suffixIndex++;} else {prefixIndex = table[prefixIndex - 1];}}return table;}// KMP算法匹配function kmpSearch(text, pattern) {const m = text.length;const n = pattern.length;const table = buildPartialMatchTable(pattern);let textIndex = 0;let patternIndex = 0;while (textIndex < m) {if (text[textIndex] === pattern[patternIndex]) { if (patternIndex === n - 1) {return textIndex - n + 1; //匹配成功,返回起始位置}textIndex++;patternIndex++;} else if (patternIndex > 0) {patternIndex = table[patternIndex - 1];} else {textIndex++;}}return -1; //匹配失败}```3.正则表达式匹配JavaScript提供了内置的正则表达式对象RegExp,可以使用正则表达式来进行字符串匹配。

模式匹配算法及应用教案

模式匹配算法及应用教案

模式匹配算法及应用教案模式匹配算法是指在一个文本字符串中查找一个给定的模式(也称为目标字符串)的算法。

在计算机科学中,模式匹配是一个非常重要的问题,在许多应用领域都有广泛的应用,如字符串匹配、数据压缩、图像处理等。

一、模式匹配算法的分类1. 朴素模式匹配算法:朴素模式匹配算法(也称为暴力算法)是一种简单直观的模式匹配算法。

它的基本思想是从目标字符串的第一个字符开始,对比目标字符串和模式字符串的每个字符是否相等,如果不等,则向右移动目标字符串一个位置,再次开始对比;如果相等,则继续对比下一个字符,直到模式字符串的所有字符都匹配成功或目标字符串结束。

朴素模式匹配算法的时间复杂度为O(mn),其中m是目标字符串的长度,n 是模式字符串的长度。

2. KMP算法:KMP算法是一种高效的模式匹配算法,它的核心思想是通过利用已匹配部分的信息来避免不必要的对比。

具体来说,KMP算法通过构建一个"部分匹配表"(也称为next数组),来记录模式字符串中每个字符前面的最长匹配前缀和后缀的长度。

在匹配过程中,当出现不匹配的字符时,可以利用部分匹配表的信息来确定下一次对比的位置,从而实现跳跃式的移动。

KMP算法的时间复杂度为O(m+n),其中m是目标字符串的长度,n是模式字符串的长度。

3. Boyer-Moore算法:Boyer-Moore算法是一种基于字符比较的模式匹配算法,它的主要思想是从目标字符串的最末尾开始比较。

通过预先计算模式字符串中的每个字符在模式字符串中最右出现的位置,可以根据目标字符串中不匹配的字符在模式字符串中的位置进行跳跃移动,从而实现快速的匹配。

Boyer-Moore算法的时间复杂度平均情况下为O(n/m),其中n是目标字符串的长度,m是模式字符串的长度。

二、模式匹配算法的应用1. 字符串匹配:字符串匹配是模式匹配算法的最常见应用之一。

在很多应用中,需要在一个文本字符串中查找给定的子字符串。

串的模式匹配算法

串的模式匹配算法

串串(String)又叫做字符串,是一种特殊的线性表的结构,表中每一个元素仅由一个字符组成。

随着计算机的发展,串在文字编辑、词法扫描、符号处理以及定理证明等诸多领域已经得到了越来越广泛的应用。

第一节串的定义和表示1、串的逻辑结构定义串是由零个到任意多个字符组成的一个字符序列。

一般记为:S=’ a1a2a3……a n’(n>=0)其中S为串名,序列a1a2a3……a n为串值,n称为串的长度,我们将n=0的串称为空串(null string)。

串中任意一段连续的字符组成的子序列我们称之为该串的子串,字符在序列中的序号称为该字符在串中的位置。

在描述中,为了区分空串和空格串(s=‘’),我们一般采用来表示空串。

2、串的基本操作串一般包含以下几种基本的常用操作:1、length(S),求S串的长度。

2、delete(S,I,L),将S串从第I位开始删除L位。

3、insert(S,I,T),在S的第I位之前插入串T。

4、str(N,S),将数字N转化为串S。

5、val(S,N,K),将串S转化为数字N;K的作用是当S中含有不为数字的字符时,K记录下其位置,并且S没有被转化为N。

3、串的储存结构一般我们采用以下两种方式保存一个串:1、字符串类型,描述为:const n=串的最大长度type strtype=string[n]这里由于tp的限制,n只能为[1..255]。

在fp或者delphi中,我们还可以使用另外一种类型,描述为:const n=串的最大长度type strtype=qstring[n]这里的n就没有限制了,只要空间允许,开多大都可以。

2、数组来保存,描述为:const n=串的最大长度type strtype=records:array[1..n] of char;len:0..n;end;第二节模式匹配问题与一般的线性表不同,我们一般将串看成一个整体,它有一种特殊的操作——模式匹配。

python字符串匹配算法

python字符串匹配算法

python字符串匹配算法一、引言在计算机科学中,字符串匹配是指在文本中查找特定模式的子串。

这种操作在很多实际应用中都非常重要,例如在文件搜索、数据过滤、自然语言处理等领域。

Python提供了一些内置函数和库,可以方便地进行字符串匹配。

二、基本算法1. 朴素字符串匹配算法(Naive String Matching):这是一种简单的字符串匹配算法,通过遍历文本串,逐个字符地与模式串进行比较,以确定是否存在匹配。

2. 暴力匹配算法(Brute Force):这是一种基于字符比较的字符串匹配算法,通过逐个字符地比较文本串和模式串,直到找到匹配或者遍历完整个文本串为止。

3. KMP算法(Knuth-Morris-Pratt Algorithm):这是一种高效的字符串匹配算法,通过记忆已经比较过的字符,减少不必要的重复比较,从而提高匹配速度。

三、Python实现1. 朴素字符串匹配算法:在Python中,可以使用`str.find()`方法或`str.index()`方法来查找模式串在文本串中的位置。

示例如下:```pythontext = "Hello, world!"pattern = "world"index = text.find(pattern)if index != -1:print("Pattern found at index", index)else:print("Pattern not found")```2. 暴力匹配算法:在Python中,可以使用`re`模块来实现暴力匹配算法。

示例如下:```pythonimport retext = "Hello, world! This is a test."pattern = "world"matches = re.findall(pattern, text)if matches:print("Pattern found in text")else:print("Pattern not found in text")```3. KMP算法:在Python中,可以使用`re`模块中的`search()`方法来实现KMP算法。

串的模式匹配算法

串的模式匹配算法

串的模式匹配算法字符串模式匹配是计算机科学中一种常用的算法。

它是一种检索字符串中特定模式的技术,可以用来在字符串中查找相应的模式,进而完成相应的任务。

字符串模式匹配的基本思想是,用一个模式串pattern去匹配另一个主串text,如果在text中找到和pattern完全匹配的子串,则该子串就是pattern的匹配串。

字符串模式匹配的过程就是在text中搜索所有可能的子串,然后比较它们是否和pattern完全匹配。

字符串模式匹配的算法有很多,其中著名的有暴力匹配算法、KMP算法、BM算法和Sunday算法等。

暴力匹配算法是最简单也是最常用的字符串模式匹配算法,其思想是从主串的某一位置开始,依次比较pattern中每一个字符,如果某个字符不匹配,则从主串的下一位置重新开始匹配。

KMP算法(Knuth-Morris-Pratt算法)是一种更为高效的字符串模式匹配算法,它的特点是利用了已匹配过的字符的信息,使搜索更加有效。

它的实现思想是,在pattern中先建立一个next数组,next数组的值代表pattern中每个字符前面的字符串的最大公共前缀和最大公共后缀的长度,这样可以在主串和模式串匹配失败时,利用next数组跳转到更有可能匹配成功的位置继续搜索,从而提高字符串模式匹配的效率。

BM算法(Boyer-Moore算法)也是一种高效的字符串模式匹配算法,它的实现思想是利用主串中每个字符最后出现的位置信息,以及模式串中每个字符最右出现的位置信息来跳转搜索,从而减少不必要的比较次数,提高搜索效率。

Sunday算法是一种简单而高效的字符串模式匹配算法,它的实现思想是,在主串中搜索时,每次从pattern的最右边开始比较,如果不匹配,则根据主串中下一个字符在pattern中出现的位置,将pattern整体向右移动相应位数,继续比较,这样可以减少不必要的比较次数,提高算法的效率。

字符串模式匹配算法的应用非常广泛,它可以用来查找文本中的关键字,检查一个字符串是否以另一个字符串开头或结尾,查找文本中的模式,查找拼写错误,检查字符串中是否包含特定的字符等。

串的两种模式匹配算法

串的两种模式匹配算法

串的两种模式匹配算法 模式匹配(模范匹配):⼦串在主串中的定位称为模式匹配或串匹配(字符串匹配) 。

模式匹配成功是指在主串S中能够找到模式串T,否则,称模式串T在主串S中不存在。

以下介绍两种常见的模式匹配算法:1. Brute-Force模式匹配算法暴风算法,⼜称暴⼒算法。

算法的核⼼思想如下: 设S为⽬标串,T为模式串,且不妨设: S=“s0s1s2…sn-1” , T=“t0t1t2 …tm-1” 串的匹配实际上是对合法的位置0≦i≦n-m依次将⽬标串中的⼦串s[i…i+m-1]和模式串t[0…m-1]进⾏⽐较:若s[i…i+m-1]=t[0…m-1]:则称从位置i开始的匹配成功,亦称模式t在⽬标s中出现;若s[i…i+m-1]≠t[0…m-1]:从i开始的匹配失败。

位置i称为位移,当s[i…i+m-1]=t[0…m-1]时,i称为有效位移;当s[i…i+m-1] ≠t[0…m-1]时,i称为⽆效位移。

算法实现如下: (笔者偷懒,⽤C#实现,实际上C# String类型已经封装实现了该功能)1public static Int32 IndexOf(String parentStr, String childStr)2 {3 Int32 result = -1;4try5 {6if (parentStr.Length > 1 && childStr.Length > 1)7 {8 Int32 i = 0;9 Int32 j = 0;10while (i < parentStr.Length && j < childStr.Length)11 {12if (parentStr[i] == childStr[j])13 {14 i++;15 j++;16 }17else18 {19 i = i - j + 1;20 j = 0;21 }22 }23if (i < parentStr.Length)24 {25 result = i - j;26 }27 }28 }29catch (Exception)30 {31 result = -1;32 }33return result;34 } 该算法的时间复杂度为O(n*m) ,其中n 、m分别是主串和模式串的长度。

【字符串匹配】BM(Boyer-Moore)字符串匹配算法详解总结(附C++实现代码)

【字符串匹配】BM(Boyer-Moore)字符串匹配算法详解总结(附C++实现代码)

【字符串匹配】BM(Boyer-Moore)字符串匹配算法详解总结(附C++实现代码)BM算法思想的本质上就是在进⾏模式匹配的过程中,当模式串与主串的某个字符不匹配的时候,能够跳过⼀些肯定不会匹配的情况,将模式串往后多滑动⼏位。

BM算法寻找是否能多滑动⼏位的原则有两种,分别是坏字符规则和好后缀规则。

坏字符规则:我们从模式串的末尾往前倒着匹配,当我们发现某个字符⽆法匹配时,我们把这个⽆法匹配的字符叫做坏字符(主串中的字符)。

此时记录下坏字符在模式串中的位置si,然后拿坏字符在模式串中查找,如果模式串中并不存在这个字符,那么可以将模式串直接向后滑动m位,如果坏字符在模式串中存在,则记录下其位置xi,那么模式串向后移动的位数就是si-xi,(可以在确保si>xi,执⾏减法,不会出现向前移动的情况)。

如果坏字符在模式串中多次出现,那我们在计算xi的时候,选择最靠后的那个,这样不会因为让模式串滑动过多,导致本来可能匹配的情况被略过。

好后缀规则:在我们反向匹配模式串时,遇到不匹配时,记录下当前位置j位坏字符位置。

把已经匹配的字符串叫做好后缀,记作{u}。

我们拿它在模式串中查找,如果找到了另⼀个跟{u}相匹配的字串{u*},那么我们就将模式串滑动到字串{u*}与主串{u}对齐的位置。

如下图所⽰:如果在模式串中找不到另⼀个等于{u}的⼦串,我们就直接将模式串滑动到主串中{u}的后⾯,因为之前的任何⼀次往后滑动,都没有匹配主串中{u}的情况。

但是这种滑动做法有点太过头了,可以看下⾯的例⼦,如果直接滑动到好后缀的后⾯,可能会错过模式串与主串可以匹配的情况。

如下图:当模式串滑动到前缀与主串中{u}的后缀有部分重合的时候,并且重回部分相等的时候,就可能会存在完全匹配的情况。

所以针对这种情况我们不仅要看好后缀在模式串中,是否有另⼀个匹配的字串,我们还要考察好后缀的后缀字串是否存在跟模式串的前缀字串匹配的情况。

如下图所⽰:最后总结如何确定模式串向后滑动的位数,我们可以分别计算好后缀和坏字符往后滑动的位数,然后取两个数中最⼤的。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

在前面的图文中,我们讲了“串”这种数据结构,其中有求“子串在主串中的位置”(字符串的模式匹配)这样的算法。

解决这类问题,通常我们的方法是枚举从A串(主串)的什么位置起开始与B串(子串)匹配,然后验证是否匹配。

假设A串长度为n,B串长度为m,那么这种方法的复杂度是O(m*n)的。

虽然很多时候复杂度达不到m*n(验证时只看头一两个字母就发现不匹配了),但是我们有许多“最坏情况”,比如:
A=“aaaaaaaaaaaaaaaaaaaaaaaaab”,B=“aaaaaaaab”。

大家可以忍受朴素模式匹配算法(前缀暴力匹配算法)的低效吗?也许可以,也许无所谓。

有三位前辈D.E.Knuth、J.H.Morris、V.R.Pratt发表一个模式匹配算法,最坏情况下是O(m+n),可以大大避免重复遍历的情况,我们把它称之为克努特-莫里斯-普拉特算法,简称KMP算法。

假如,A=“abababaababacb”,B=“ababacb”,我们来看看KMP是怎样工作的。

我们用两个指针i和j分别表示,。

也就是说,i是不断增加的,随着i 的增加j相应地变化,且j满足以A[i]结尾的长度为j的字符串正好匹配B串的前j个字符(j当然越大越好),现在需要检验A[i+1]和B[j+1]的关系。

例子:
S=“abcdefgab”
T=“abcdex”
对于要匹配的子串T来说,“abcdex”首字符“a”与后面的串“bcdex”中任意一个字符都不相等。

也就是说,既然“a”不与自己后面的子串中任何一字符相等,那么对于主串S来说,前5位字符分别相等,意味着子串T的首字符“a”不可能与S串的第2到第5位的字符相等。

朴素算法步骤2,3,4,5的判断都是多余,下次的起始位置就是第6个字符。

例子:
S=“abcabcabc”
T=“abcabx”
如果T串后面也含有首字符“a”。

对于开始的判断,前5个字符完全相等,第6个字符不等,此时,根据刚才的经验,T的首字符“a”与T的第二位字符“b”、第三位字符“c”均不等,所以不需要做判断,朴素算法步骤2,3都是多余。

因为T的首位“a”与T第四位“a”相等,第二位的“b”与第五位的“b”相等。

而第四位的“a”与第五位的“b”已经与主串S中的相应位置比较过了,是相等的,因此可以断定,T的首字符“a”、第二位的字符“b”与S的第四位字符和第五位字符也不需要比较了,下次的起始位置就是6,T的起始位置就是第3个字符。

对比这两个例子,可知两种情况下主串当前位置的都是第6个字符。

要考虑的变化就是子串的下标j值了。

通过观察也可发现,我们屡屡提到了T串的首字符与自身后面字符的比较,发现如果有相等字符,j值的变化就会不相同。

也就是说,这个j值的变化与主串其实没什么关系,关键就取决于T串的结构中是否有重复的问题。

下面按照程序的方式来介绍,字符串第一个字符的下标为0。

由于T=“abcde x”,当中没有任何重复的字符,所以j就由5变成了0。

由于T=“abcab x”,前缀的“ab”与后面“x”之前串的后缀“ab”是相等的。

因此j就由5变成了2。

因此,我们可以得出规律,j值的多少取决于当前字符之前的串的前,后缀的相似度。

我们把T串各个位置的j值的变化定义为一个数组next,那么next的长度就是T串的长度。

于是我们可以得到下面的定义:
起始字符 next[0] = -1;
如果后面没有与起始字符相同的字符则next[i] = 0;
如果后面有与起始字符相同的字符则next[i] = -1;与前缀进行匹配,匹配完毕的后一位的j值记录匹配字符的个数。

其他next[i] = 0;
即next[i]的值表示,第i位不同时,j的取值。

具体构造方法查看后面代码。

例子:
T=“abcdex”
Next = -100000
例子:
T=“abcabx”
Next = -100-102
例子:
T= “aaaaaaaab”
Next = -1-1-1-1-1-1-1-17
例子:
T =“ababacb”
Next = -10-10-130
讲完原理之后,我们利用策略模式作为解决相同问题利用不同算法的解决方案。

namespace StringMatching
{
public abstract class StringMatchingStrategy
{
public abstractint StringMatchingAlgorithm(string source, string substr);
}
}
namespace StringMatching
{
public class KmpMatching: StringMatchingStrategy {
privateint[] GetNext(string substr)
{
if(substr == null)
thrownew ArgumentException("subs tr");
int i =0, j = -1;
int[]nextVal = new int[substr.Length];
nextVal[0] = -1;
while(i < substr.Length - 1)
{
if(j == -1 || substr[i] ==
substr[j])
{
i++;
j++;
if(substr[i] != substr[j])
nextVal[i] = j;
else
nextVal[i]
=nextVal[j];
}
else
{
j = nextVal[j];
}
}
return nextVal;
}
public override int StringMatchingAlgorithm(stri ng source, string substr)
{
if(source == null)
thrownew ArgumentException("sour ce");
if(substr == null)
thrownew ArgumentException("subs tr");
int i = 0, j = 0, v;
int[]nextVal = GetNext(substr);
while(i < source.Length && j <
substr.Length)
{
if(j == -1 || source[i] == substr[j])
{
i++;
j++;
}
else
{
j = nextVal[j];
}
}
if(j >= substr.Length)
v = i - substr.Length;
else
v = -1;
return v;
}
}
}
namespace StringMatching
{
public class PrefixBruteForceMatching: StringMatchingS trategy
{
public override int StringMatchingAlgorithm(stri ng source, string substr)
{
if(source == null)
thrownew ArgumentException("sour ce");
if(substr == null)
thrownew ArgumentException("subs tr");
for(int i = 0; i <= source.Length
-substr.Length; i++)
{
if(source[i] == substr[0])
{
int j = 1;
for(; j < substr.Length; j++)
{
if(substr[j] != source[i + j])
break;
}
if(j == substr.Length)
return i;
}
}
return-1;
}
}
}。

相关文档
最新文档