【问题标题】:Regular expression is too complex error in tcltcl中的正则表达式太复杂错误
【发布时间】:2021-03-31 05:38:35
【问题描述】:

对于一个小列表,我没有看到这个错误。当列表大于 10k 时弹出问题。 tcl 中正则表达式的数量有限制吗?

puts "#LEVELSHIFTER_TEMPLATES_LIMITSFILE:$perc_limit(levelshifter_templates)"
puts "#length of templates is :[llength $perc_limit(levelshifter_templates)]"
if { [regexp [join $perc_limit(levelshifter_templates) |] $temp] }

#LEVELSHIFTER_TEMPLATES_LIMITSFILE:HDPELT06_LVLDBUF_CAQDP_1 HDPELT06_LVLDBUF_CAQDPNRBY2_1 HDPELT06_LVLDBUF_CAQDP_1....
#length of templates is :13520
ERROR: couldn't compile regular expression pattern: regular expression is too complex

【问题讨论】:

  • 我尝试了一个较小的列表,如果列表最多包含 1950 个元素,则看不到错误。我认为使用这个命令是有上限的。
  • 有些东西让 RE 引擎抱怨构建它所需的堆栈深度。哪个……是我以前在生产中从未见过的!但是我从未见过大小必须在 100kB 左右的 RE。呸!

标签: regex tcl


【解决方案1】:

如果$temp 是一个单词,而您实际上只是在进行文字测试,则应该反转检查。最简单的方法之一可能是:

if {$temp in $perc_limit(levelshifter_templates)} {
    # ...
}

但是,如果您经常这样做(嗯,不止几次,比如说 3 或 4 次),那么为此构建一个字典可能是最好的:

# A one-off cost
foreach key $perc_limit(levelshifter_templates) {
    # Value is arbitrary
    dict set perc_limit_keys $key 1
}

# This is now very cheap
if {[dict exists $perc_limit_keys $temp]} {
    # ...
}

如果$temp 中有多个单词,请拆分并检查(使用第二种技术,现在绝对值得)。这是一个很好的计划。

proc anyWordIn {inputString keyDictionary} {
    foreach word [split $inputString] {
        if {[dict exists $keyDictionary $word]} {
            return true
        }
    }
    return false
}

if {[anyWordIn $temp $perc_limit_keys]} {
    # ...
}

【讨论】:

  • 这是一个很好的解决方案,但不适用于带有 * 和其他正则表达式的模式。如果我有一个包含 10,000 多个正则表达式模式的列表,我想与单元名称 $temp 匹配,它会给出正则表达式太复杂的错误。
【解决方案2】:

假设您想查看temp 中的值是否与perf_limit(levelshifter_templates) 中的列表元素之一完全匹配,这里有一些比尝试使用正则表达式更好的方法:

使用lsearch`:

# Sort the list after populating it so we can do an efficient binary search
set perf_limit(levelshifter_templates) [lsort $perf_limit(levelshifter_templates)]

# ...

# See if the value in temp exists in the list
if {[lsearch -sorted $perf_limit(levelshifter_templates) $temp] >= 0} {
    # ...
}

提前将列表的元素存储在字典(或数组,如果您愿意)中以进行O(1) 查找:

foreach item $perf_limit(levelshifter_templates) {
    dict set lookup $item 1
}

# ...

if {[dict exists $lookup $temp]} {
    # ...
}

【讨论】:

    【解决方案3】:

    我找到了解决此问题的简单解决方法,方法是使用 foreach 语句循环列表中的所有正则表达式,而不是加入它们并搜索,这对于超长列表失败。

    foreach pattern $perc_limit(levelshifter_templates) {
        if { [regexp $pattern $temp]} 
            #puts "$fullpath: [is_std_cell_dev $dev]"
            puts "##matches: $pattern return 0"
            return 0
        }
    } 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-22
      • 1970-01-01
      • 1970-01-01
      • 2016-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-21
      相关资源
      最近更新 更多