Alan Saldanha
Alan Saldanha

Reputation: 87

Regular expression is too complex error in tcl

I have not seen this error for a small list. Issue popped up when the list went >10k. Is there any limit on the number of regex patterns in 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

Upvotes: 0

Views: 297

Answers (3)

Alan Saldanha
Alan Saldanha

Reputation: 87

I found a simple workaround for this problem by using a foreach statement to loop over all the regexes in the list instead of joining them and searching, which failed for a super-long list.

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

Upvotes: 0

Donal Fellows
Donal Fellows

Reputation: 137577

If $temp is a single word and you're really just doing a literal test, you should invert the check. One of the easiest ways might be:

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

But if you're doing that a lot (well, more than a small number of times, 3 or 4 say) then building a dictionary for this might be best:

# 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]} {
    # ...
}

If you've got multiple words in $temp, split and check (using the second technique, which is now definitely worthwhile). This is where having a helper procedure can be a good plan.

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

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

Upvotes: 2

Shawn
Shawn

Reputation: 52374

Assuming you want to see if the value in temp is an exact match for one of the elements of the list in perf_limit(levelshifter_templates), here's a few ways that are better than trying to use regular expressions:

Using 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} {
    # ...
}

Storing the elements of the list in a dict (or array if you prefer) ahead of time for an O(1) lookup:

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

# ...

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

Upvotes: 1

Related Questions