含单词边界的正则提取Verilog模块内容无输出问题求助
用Tcl提取Verilog模块内容遇到的问题
我需要编写Tcl代码,提取字符串中从module起始标签到endmodule结束标签之间的所有内容,将每个匹配的完整模块存入数组。我给标签加了\b单词边界确保精确匹配,同时用.*?实现非贪婪匹配,但试了三种方案都没有输出结果。
示例字符串
set verilog_string { module first_module; // Verilog code //jhkjhkh endmodule non-module code 123 456... module second_module; //code2 //lkjkjljk //jkjhkhjkjhkh endmodule }
预期结果
数组第1项内容:
module first_module; // Verilog code //jhkjhkh endmodule
数组第2项内容:
module second_module; //code2 //lkjkjljk //jkjhkhjkjhkh endmodule
尝试的三种方案
Attempt 1
proc extract_verilog_modules {verilog_string} { set content $verilog_string set modules_list {} # Match 'module' to 'endmodule' including multiline matches set module_pattern {\bmodule\b.*?\bendmodule\b} foreach module [regexp -all -inline $module_pattern $content] { puts "here" lappend modules_list $module } return $modules_list } set extracted_modules [extract_verilog_modules $verilog_string] puts "here 1" foreach module $extracted_modules { puts "Extracted Module:\n$module" } puts "here 2"
Attempt 2
proc extract_verilog_modules {verilog_string} { set content $verilog_string set modules_list {} set module_pattern {(?m)^\s*module\b.*?(?:(?=\n\s*endmodule\b)|(?=endmodule\b))} set endmodule_pattern {endmodule\b} foreach module_match [regexp -all -inline -- $module_pattern $content] { set line_number [lsearch -inline -regexp [split $content "\n"] [string trimleft $module_match]] set char_position [string first $module_match $line_number] set module_content "" set in_module 1 foreach line [split $module_match "\n"] { if {$in_module} { append module_content "$line\n" } if {[regexp $endmodule_pattern $line]} { set in_module 0 } } lappend modules_list [list $module_content $line_number $char_position] } return $modules_list }
Attempt 3
proc extract_verilog_modules {verilog_string} { set content [string map {"\t" " "} $verilog_string] set content [regsub -all {(?:\r?\n|\n\r)} $content "\t"] set modules_list {} set module_pattern {\s*module\b} set endmodule_pattern {endmodule\b} set module_index 0 set endmodule_index 0 while {[regexp -start $module_index -- $module_pattern $content -> module_start]} { set module_end [expr {$module_start + $module_index + [string length "module"]}] set module_index [expr {$module_end}] if {[regexp -start $endmodule_index -- $endmodule_pattern $content -> endmodule_start]} { set endmodule_end [expr {$endmodule_start + $endmodule_index + [string length "endmodule"]}] set endmodule_index [expr {$endmodule_end}] set module_content [string range $content $module_start $endmodule_end] set module_content [string map {"\t" "\n"} $module_content] set original_content [string map {"\t" "\n"} $content] set lines [split $original_content "\n"] set line_number 1 foreach line $lines { if {[string first $module_content $line] >= 0} { break } incr line_number } set char_position [string first $module_content $line] lappend modules_list [list $module_content $line_number $char_position] } else { break } } if {[llength $modules_list] == 0} { puts "No matches found for the regex pattern." } return $modules_list }
问题分析
- Attempt 1:Tcl默认正则中
.不匹配换行符,.*?只能匹配单行内容,无法覆盖跨多行的模块。 - Attempt 2:多行模式
(?m)仅影响^和$的匹配范围,.*?仍受限于单行,且正则逻辑未正确覆盖完整模块内容。 - Attempt 3:手动索引计算逻辑错误,替换换行符为制表符的操作增加了复杂度,导致内容截取错误。
正确实现代码
proc extract_verilog_modules {verilog_string} { set modules_list {} # (?s)让.匹配所有字符(含换行),非贪婪匹配确保匹配最近的endmodule set module_pattern {(?s)\bmodule\b.*?\bendmodule\b} # 遍历所有匹配结果,偶数索引为完整匹配项 foreach {match} [regexp -all -inline $module_pattern $verilog_string] { # 去除末尾多余换行(可选,按需调整) set match [string trimright $match "\n"] lappend modules_list $match } return $modules_list } set extracted_modules [extract_verilog_modules $verilog_string] # 输出结果 set idx 0 foreach module $extracted_modules { incr idx puts "第$idx个提取的模块:\n$module\n" }
代码说明
(?s):单行模式修饰符,让.匹配包括换行在内的所有字符,解决跨多行匹配问题。\bmodule\b/\bendmodule\b:确保匹配完整单词,避免误匹配包含这些字符串的其他标识符。.*?:非贪婪匹配,保证从当前module匹配到最近的endmodule,不会跳过中间模块。regexp -all -inline:直接返回所有匹配的完整模块内容,遍历即可存入数组。
内容的提问来源于stack exchange,提问作者Bimo
相关产品推荐
相关产品推荐

