Javascript 在正则表达式中创建第n层嵌套模式的算法
如中所述,不可能创建正则表达式来匹配任意嵌套模式。但是,有没有可能创建一个算法来生成第n级“嵌套”的正则表达式 基本上,我想用Javascript 在正则表达式中创建第n层嵌套模式的算法,javascript,regex,algorithm,recursion,Javascript,Regex,Algorithm,Recursion,如中所述,不可能创建正则表达式来匹配任意嵌套模式。但是,有没有可能创建一个算法来生成第n级“嵌套”的正则表达式 基本上,我想用rtrim(ltrim(whatever))替换trim(whatever) 我设法手动创建了3个级别(javascript语法): level[1]=/\([^()]*)\)/g 级别[2]=/\((((?:[^()]*\([^()]*\)*[^()]*])\)/g 级别[3]=/\((((?:(?:(?:[^()]*\([^()]*\)*\((?:(?:[^()]*\
rtrim(ltrim(whatever))替换trim(whatever)
我设法手动创建了3个级别(javascript语法):
level[1]=/\([^()]*)\)/g
级别[2]=/\((((?:[^()]*\([^()]*\)*[^()]*])\)/g
级别[3]=/\((((?:(?:(?:[^()]*\([^()]*\)*\((?:(?:[^()]*\([^()]*\)*([^()]*\)*[^()]*)*[^()]*)/g
以下是一些测试数据:
1st(ddd) + 1st(ddd)
2nd(dd(d))
3rd(a(b) + (cd(h) + d(dfas) + zzz))
4th(a(b(c(d))))
8th(a(b(c(d(e(f(g()))))))
我知道在每个级别上,[^()]*
都需要替换为可以包含括号的非捕获组,但是我不知道如何将算法推广到第n级。你可以从理论上更深入地思考:括号嵌套的n
deep的匹配只是围绕n-1
或更低深度的匹配的括号(至少有一个正好n-1
deep)
我们可以给出正则表达式的递归定义。设X[n]
为精确嵌套n
级别的正则表达式,Y[n]
为包含任何嵌套级别的括号的字符串的正则表达式,直到n
级别,因此:
X[n] = \( (Y[n-2] X[n-1])+ Y[n-2] \)
Y[n] = [^()]* ( \( Y[n-1] \) [^()]* )*
使用Y[0]=X[0]=[^()]*
(无嵌套)和X[1]=\([^()]*\)
。(我还不在乎非捕获组等的细节,这些空间只是为了可读性。)
基于此编写算法应该很容易
来自这些新定义(较少相互递归)的正则表达式变得更长更慢(它们是多项式而不是指数)
假设l[n]
是X[n]
的长度,l[n]
是Y[n]
的长度,那么(常数项只是每个常数项中的硬编码字符):
使用l[0]
和l[1]
的适当初始条件。这种形式的递推关系有二次解,所以这只是O(n^2)
。好多了
(对于其他人,我以前对Y[n]
的定义是Y[n]=Y[n-1]|X[n]
;这个额外的递归意味着X
正则表达式的长度是O(2.41^n)
,这很糟糕。)
(对Y
的新定义是一个诱人的暗示,甚至可能有一种书写X
的方式,在n
中是线性的。不过我不知道,我感觉对X
的额外限制精确长度意味着这是不可能的。)
下面是一些计算上述正则表达式的Python代码,您可能不需要太多麻烦就可以将其转换为javascript
# abbreviation for the No Parenthesis regex
np = "[^()]*"
# compute Y[n] from Y[n-1]
def next_y(y_n1):
return np + "(?:\(" + y_n1 + "\)" + np + ")*"
# compute X[n] from X[n-1] and Y[n-2]
def next_x(x_n1, y_n2):
return "\((?:" + y_n2 + x_n1 + ")+" + y_n2 + "\)"
# compute [X[n], Y[n], Y[n-1]]
# (to allow us to make just one recursive call at each step)
def XY(n):
if n == 0:
return [np, # X[0]
np, # Y[0]
""] # unused
elif n == 1:
return ["\([^()]*\)", # X[1]
next_y(np), # Y[1]
np] # Y[0]
x_n1, y_n1, y_n2 = XY(n-1) # X[n-1], Y[n-1], Y[n-2]
return [next_x(x_n1, y_n2), # X[n]
next_y(y_n1), # Y[n]
y_n1] # Y[n-1]
# wrapper around XY to compute just X[n]
def X(n):
return XY(n)[0]
# wrapper around XY to compute just Y[n]
def Y(n):
return XY(n)[1]
谢谢,O()不是问题,我希望没有人会使用超过10个嵌套括号,我会在周末看一看:)@deathApril,我刚刚通过更改Y
的定义大大改进了答案。这将n=10
的正则表达式的大小从~45000减少到~1500(因此,即使对于10
来说,O()也使正则表达式变得巨大!)。(我知道你并不担心大型n
,但我觉得这个问题很有趣(谢谢你问!),所以我还是在做分析。)@deathApril,现在有一些代码(虽然是Python而不是Javascript)。很高兴听到这个问题对你来说很有趣-我的工作量更少;)python还可以,我只需运行它并在记事本++宏中使用生成的正则表达式(或者我创建一个简单的web应用程序来实现它,如果其他团队成员想使用它的话)——我会在对它进行更多测试后接受;)
# abbreviation for the No Parenthesis regex
np = "[^()]*"
# compute Y[n] from Y[n-1]
def next_y(y_n1):
return np + "(?:\(" + y_n1 + "\)" + np + ")*"
# compute X[n] from X[n-1] and Y[n-2]
def next_x(x_n1, y_n2):
return "\((?:" + y_n2 + x_n1 + ")+" + y_n2 + "\)"
# compute [X[n], Y[n], Y[n-1]]
# (to allow us to make just one recursive call at each step)
def XY(n):
if n == 0:
return [np, # X[0]
np, # Y[0]
""] # unused
elif n == 1:
return ["\([^()]*\)", # X[1]
next_y(np), # Y[1]
np] # Y[0]
x_n1, y_n1, y_n2 = XY(n-1) # X[n-1], Y[n-1], Y[n-2]
return [next_x(x_n1, y_n2), # X[n]
next_y(y_n1), # Y[n]
y_n1] # Y[n-1]
# wrapper around XY to compute just X[n]
def X(n):
return XY(n)[0]
# wrapper around XY to compute just Y[n]
def Y(n):
return XY(n)[1]