正则表达式中有没有短路求值这样的东西?如果有,应该怎么写?
我想把它做成SQLite Tcl接口中的一个应用程序定义函数,以便在WHERE子句中使用,用来检查一个JSON数组($jarray)是否包含另一个JSON数组($jnodes)中的任意一个元素。我不想从正则表达式中捕获任何内容,只需要一个0/1的返回值。
我以为括号定义了一个捕获组,但没有括号就得不到正确的结果。有没有办法写出正则表达式,使其不捕获任何内容并在第一次匹配时就停止搜索?
我并没有遇到性能问题,主要是出于学习和好奇心来问问。
proc InJSONArray {jarray jnodes} {
#set $node [join [split [string range $p 1 end-1] ,] |]
set rnodes [string map {, |} [string range $jnodes 1 end-1] ]
return [regexp "(\\\[|,)($rnodes)(,|\\\])" $jarray]
}
set j {[22,18,49,76,37,45,16]}
set n1 {[12,58,93,67]}; # not matches
set n2 {[32,84,37,14]}; # matches 37
InJSONArray $j $n1
# 0
InJSONArray $j $n2
# 1
首先,我尝试了两个 foreach,而不是 in,大约是3.5–3.9微秒。因此,我猜对于这组数据,循环和正则表达式的花费大致相同。
proc Intersect {jarray jnodes} {
set nodes [split [string range $jnodes 1 end-1] ,]
set array [split [string range $jarray 1 end-1] ,]
foreach n $nodes {
if { $n in $array } {return 1}
}
return 0
}
proc InJSONArray {jarray jnodes} {
return [regexp "(\\\[|,)([string map {, |} [string range $jnodes 1 end-1] ])(,|\\\])" $jarray]
}
set j {[22,18,49,76,37,45,16]}
set n1 {[12,58,93,67]}; # not matches
set n2 {[32,84,37,14]}; # matches 37
% timerate {Intersect $j $n1} 5000
1.932625 µs/# 2587155 # 517431 #/sec 5000.000 net-ms
% timerate {Intersect $j $n2} 5000
1.835088 µs/# 2724665 # 544933 #/sec 5000.000 net-ms
% timerate {InJSONArray $j $n1} 5000
1.779623 µs/# 2809584 # 561916 #/sec 5000.000 net-ms
% timerate {InJSONArray $j $n2} 5000
1.617978 µs/# 3090277 # 618055 #/sec 5000.000 net-ms
解决方案
有没有办法写出正则表达式,使其不捕获任何内容并在首次匹配时就停止搜索?
默认就是这样。你必须使用 -all 开关让它搜索所有匹配并返回找到的数量。没有这个开关,它在找到第一个匹配时就直接返回 1。
关于你提到的其他一些问题,你可以使用 (?:...) 来创建一个非捕获组。你还可以使用 [[,] 来匹配方括号或逗号,而不是在一个组中用 \[|, 进行交替。或者使用 [[:<:]] 和 [[:>:]] 分别匹配单词的起始和结束,而不是显式地匹配标点字符。于是,正则表达式可以是
[[:<:]](?:$rnodes)[[:>:]]
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。