您现在的位置是:主页 > news > wordpress 2栏主题/首页关键词优化价格
wordpress 2栏主题/首页关键词优化价格
admin2025/5/23 17:29:15【news】
简介wordpress 2栏主题,首页关键词优化价格,大连工业,微信公众号的开发本文是5分钟理解CFG上下文无关文法的续集,在5分钟理解CFG上下文无关文法这篇文章中已经讲解了CFG的基本概念,但是CFG的解析算法才是核心。由于它的解析算法极其复杂,网上很少有文章能把解析算法用大众能理解的语言写出来,本人在理…
本文是5分钟理解CFG上下文无关文法的续集,在5分钟理解CFG上下文无关文法这篇文章中已经讲解了CFG的基本概念,但是CFG的解析算法才是核心。由于它的解析算法极其复杂,网上很少有文章能把解析算法用大众能理解的语言写出来,本人在理解了算法后用python代码实现了算法,通过测试用例验证了该算法的正确性,当然也验证了我理解的是正确的。
这里说的解析其实就是验证一个输入字符串input是否符合给定的文法G,实现算法有CYK解析算法,和Eerley解析算法,都是是以人名命名。下面介绍Eerley解析算法
假设input的字符串是” 2021年2月1日”,验证是否符合下面定义的日期类文法,下面竖线|表示“或”,DIG0_9->ZERO | DIG1_9 实际上等价于2条规则:DIG0_9->ZERO;DIG0_9->DIG1_9。#后面是注释。
S->Y M D #year month day
Y->YN YT #YN:year number;YT:year tag
YT->"年"
M->MN MT #MN:month number; MT:month tag
MN-> DOZEN #1 到12
MT->"月"
DT->"日"
YN->DIG1_9 DIG0_9 DIG0_9 DIG0_9 # DIG1_9:digit 1 to 9
DIG0_9->ZERO | DIG1_9
DIG1_9->ONE | DIG2_9
DIG2_9->TWO | DIG3_9
DIG3_9-> THREE | DIG4_9
DIG4_9->"4" | "5" |"6" |"7" |"8" | "9"
ZERO->"0"
ONE->"1"
TWO->"2"
THREE->"3"
DOZEN ->DIG1_9 | ZERO DIG1_9 | ONE ZERO | ONE ONE | ONE TWO
D->DN DT
DN-> DIG1_9 | ZERO DIG1_9 | ONE DIG1_9 | TWO DIG1_9 | THREE ZERO | THREE ONE
预备知识:
- Dot rule: 点规则A->β·α在规则A->B α的基础上加上一个点表示目前匹配到的情况,点·的左边已经正确匹配到input某段字符串,·的右边为待匹配的部分。
- 命名规范:大写英文字母(可以多个)表示非终结符(也叫变量)如A,小写英文字母表示终结符如a,小写希腊字母表示或者终结符或者非终结符,且可以为空,如α。
- 假设输入字符串input的长度为n,定义位置号position是每个字符的边界:
Input: a0 a1 a2… a(n-1)
Position: 0 1 2 3 ... n-1 n
上面子字符串“a1 a2”起始位置start=1,结束位置end=3
- 构造一个n+1行,n+1列的表格C,记录所有子串的匹配状态。行号表示子串起始位置start的取值,列号表示结束位置。C(1,3)表示第1行,第3列的格子,里面的值是子串“a1 a2”(起始位置是1,结束位置是3)的匹配规则及匹配状态。每个格子是一个set,set里放的是匹配到该子字符串的若干条规则,并以dot rule标记。注意set会自动过滤重复的值。比如 A->β·α 放在C(1,3)里表示,规则中β部分匹配了input中的位置1到位置3的子串“a1 a2”,后面的部分α是否匹配不知道,待后面处理,且α可以是空字符串。由于起始位置小于等于结束位置,下面表格灰色部分不可能有数据。
算法步骤
4个主要步骤:初始化,prediction(自顶向下扩展变量),scanning(对终结符与输入字符比较看是否匹配上),completion(自底向上合并,即将低层相邻的变量或终结符合并成高层的变量)
- 初始化1:算出输入字符串长度n,构造n+1行n+1列的C表格,把所有顶层规则S->·α放在C(0,0),表示规则匹配到0到0的的空字符串,·后边的α等待被进一步处理。
- 初始化2:构造n+1个先进先出的队列组成的数组q[],为每一列C表格记录规则的产生和处理的情况,防止重复处理。用元组(规则r,起始位置i,结束位置j)来表示规则r放在C(i,j)格子中,在每次向C表格中添加一条规则时,同时在队列q中压入一个元组(规则,起始位置,结束位置),处理时先弹出规则元组。
- 在日期类的例子中,顶层规则只有一条,是S->Y M D,往C(0,0)放入S->·Y M D,并往q中压入元组(S->·Y M D,0,0)
- 第一层循环:for结束位置j=0 to n
- 第二层循环: while(q[j]不为空)
- 从q[end]中弹出一条规则和位置组成的元组。
- If(规则没有完全匹配某段字串,也就是规则中的点·不在最后):#第一层if
- If(规则待处理的是个非终结符或称为变量): #第二层if
- 做prediction,即扩展变量。具体地:
- 可以用(A->β·Yα,i,j)表示该规则,即·后面待处理的是个非终结符Y,β匹配了位置i到j之间的子字符串,β和α可以为空,当β空时,i和j相等。遍历规则集,找到所有扩展Y的规则 Y->γ(可能有多条规则,不同的规则,γ值不同),在C(i,j)中添加规则Y->·γ,并在q[j]中压入(Y->·γ,j,j),注意Y->·γ匹配的起始点是j不是i,而j表示弹出的规则(A->β·Yα,i,j)元组的结束位置。
- 在日期类例子中,第一次弹出的是(S->·Y M D,0,0),即β为空,i=j=0。遍历规则集可以找到Y->YN YT,将Y->·YN YT添加到C(0,0)的set中。并将元组(Y->·YN YT,0,0)压入到q[0]中。在反复循环使得变量一层层扩展,最终会出现终结符,最终放入C表格和压入q[0]规则可能出现这样的:ONE->·”1”, TWO->·”2”
- Else if(规则待处理的是个终结符): #对应第二层if
- 做scanning,即把终结符与输入相应位置j到j+1之间的字符比较,看是否匹配。如果匹配上,该规则可以用(A->βa(j+1)·α,i,j+1) 表示,其中a(j+1)是input中第j+1个字符,代替了原规则里的Y,点·在原规则的基础上由β后面移动到a(j+1)后面。将规则A->βa(j+1)·α放入C(i,j+1),并将元组(A->βa(j+1)·α,i,j+1)压入q[j+1]。
- 在日期类例子中, TWO->·”2” 中最靠近·的终结符”2”与位置0到1之间的字符“2”相同则把规则TWO->”2”· 加入到C(0,1), 把(TWO->”2”·,0,1)加入到q[1]。而弹出的ONE->·”1”中终结符“1”,与位置0到1之间的字符“2”不同,则没匹配上,忽略后面的规则添加和元组压入队列的动作。
- Else if (规则完全匹配某段字串,即规则中的点·在最后): #对应第一层if
- 该规则可以用(Y->α·,i,j)表示,α不为空,α已经匹配了i到j之间的子字符串。
- 做completion,可理解为合并变量。具体地:
- 在C的第i列中查找符合A->β·Yα特征的规则,即β已经匹配到从某位置(假设k,k<i)到i之间的子字符串,点·后面紧跟着待处理的是个非终结符,且与当前规则Y->α·左侧非终结符相同,都是Y。由于A->β·Yα已经匹配到k到i的子串,而Y已经匹配到i到j的子串,因此合并后就是βY匹配到k到j之间的子串,因此将A->βY·α放入到C(k,j)(A->βY·α,k,j)压入q[j]
- 在日期类例子中,当结束位置j增加到2时,从q[2]弹出的元组会出现(ZERO->”0”·,1,2),这表示ZERO->”0”的右边“0”匹配了位置1到位置2的子串,在C的第1列中遍历,可以在C(0,1)找到规则S->”2” · ZERO D0_9 D0_9,其·后面的待处理变量=ZERO,与ZERO->”0”·的左边变量相同,则可以合并得到新的规则元组(S->”2” ZERO· D0_9 D0_9,0,2),表示S->”2” ZERO· D0_9 D0_9匹配到0到2之间的子串。
- 退出第二层while循环
- 退出第一层for循环
- 最后检查C(0,n)是否存在符合S->β·特征的规则,即左边是顶层变量S,右侧点出现在最后,表示S匹配了0到n之间的子串,即整个input。如果是,则表示验证成功,否则验证失败,字符串input不符合文法。