You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

含单词边界的正则提取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
}

问题分析

  1. Attempt 1:Tcl默认正则中.不匹配换行符,.*?只能匹配单行内容,无法覆盖跨多行的模块。
  2. Attempt 2:多行模式(?m)仅影响^和$的匹配范围,.*?仍受限于单行,且正则逻辑未正确覆盖完整模块内容。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 00:15:04