python正则
一、公共基础符号(出现在多个模式中)
| 符号 | 名称 | 作用 | 示例 |
|---|---|---|---|
\b |
单词边界 | 匹配一个位置,该位置一侧是单词字符(\w),另一侧不是。保证匹配完整的单词,不会匹配 inputwire 中的 input。 |
\binput\b 匹配 " input" 但不匹配 "inputwire"、"iinput wire" |
\s |
空白字符 | 匹配任意空白符(空格、制表符、换行等) | \s+ 匹配一个或多个空白 |
\w |
单词字符 | 匹配 [A-Za-z0-9_] |
\w+ 匹配 "clk_100" |
+ |
量词(一次或多次) | 修饰前面的原子,表示至少出现1次 | \s+ 至少一个空白 |
? |
量词(零次或一次) | 修饰前面的原子,表示出现0次或1次(即可选) | \s+? 懒惰匹配(但这里是非贪婪) |
* |
量词(零次或多次) | 修饰前面的原子,表示可以出现任意次(包括0次) | \s* 零个或多个空白 |
[ ] |
字符类 | 匹配方括号内列举的任意一个字符 | [^\]] 匹配除了 ] 以外的任意字符 |
^ |
取反(在字符类开头) | 在字符类 [^...] 中表示否定,匹配不在括号内的字符 |
[^\]] 匹配不是 ] 的字符 |
\ |
转义 | 将特殊字符转义为字面意义,或者引入特殊序列 | \] 匹配字面右方括号 |
( ) |
捕获分组 | 将括号内的表达式作为一个组,并且捕获匹配的文本,供后续提取或反向引用 | (\w+) 捕获端口名 |
(?: ) |
非捕获分组 | 仅用于分组或应用量词,不捕获文本,不保存到结果中 | (?:\s*,\s*(\w+)) 整体作为一个组,但不捕获 |
| ` | ` | 或 | 分隔两个子表达式,匹配其中任意一个 |
二、针对每个模式的具体解释
2. pattern2 = r'\binput\s+\w+\s+(\w+)'
| 符号序列 | 详细解释(包含“后面有无空格”的影响) |
|---|---|
\binput |
\b 是单词边界位置,只要求 input 前面是边界(行首/空格/标点),不关心后面;input 后面有无空格不影响本段匹配,但若后面紧接字母(如 inputwire),则后续 \s+ 会失败 |
\s+ |
匹配至少一个空白字符(空格/制表符);后面必须紧跟空白,若 input 后面无空白(如直接换行或字母),则整个匹配失败;若有多个空白,\s+ 会全部消耗掉 |
\w+ |
匹配至少一个单词字符(字母/数字/下划线);后面有无空格取决于下一个符号:若下一个是 \s+,则 \w+ 后面必须有空白才能继续;若下一个是其他(如 $),则无空格也可;此处 \w+ 后面是 \s+,所以 \w+ 后面必须紧跟空白才能匹配成功 |
\s+ |
同上,要求前一个 \w+(类型关键字)后面必须有至少一个空白,否则匹配失败 |
(\w+) |
捕获端口名;后面有无空格不影响本捕获组的匹配(因为它是最后一个元素),但如果后面还有字符(如逗号或换行),则不会影响已经捕获的内容;注意:若端口名后面直接跟非空白字符(如 clk,),则 \w+ 会匹配 clk 而停止于逗号,因为逗号不是单词字符 |
补充说明:
\s+后面有无空格:\s+本身消耗空白,它后面如果紧跟\w+,则中间不需要额外空格,因为\s+已经处理了所有空白。\w+后面有无空格:取决于下一个正则原子。若下一个原子是\s+,则\w+后面必须有空白;若下一个原子是\b或$或[等,则后面可能没有空白。\b后面有无空格:\b不消耗字符,所以\binput中\b后面直接是i,没有空格问题。但input\b要求t后面是边界,此时空格是边界的一种,所以input后面有空格时\b成立,无空格但跟字母时\b不成立。
整体作用:匹配不带位宽的输入端口,返回端口名。
3. pattern3 = r'\binput\s+\w+\s+(?:(\[[^\]]+\])\s+)?(\w+)'
不必须顶格,前面可以有空格。
原因:正则表达式中的 \b 匹配单词边界。在字符串 " input"(前面有空格)中,空格字符与 i 之间是一个单词边界(因为空格不是单词字符,i 是单词字符),因此 \binput 能够成功匹配。同样,行首、标点符号与 i 之间也是边界。所以 \binput 可以匹配:
"input"(行首)" input"(前面有空格)",input"(前面有逗号)
| 符号序列 | 基础符号含义(\b:边界;\s:空白;\w:单词字符;\d:数字;+:一次或多次;?:零或一次;*:零或多次;( ):捕获分组;(?: ):非捕获分组;[ ]:字符类;[^]:否定字符类;|:或;^:行首;$:行尾;.:任意字符(除换行);\[ \]:字面方括号) |
|---|---|
\binput\s+\w+\s+ |
匹配独立单词input后跟至少一个空白,再跟wire等类型关键字后跟至少一个空白;\s+要求后面必须有空白,若input后无空白或wire后无空白则匹配失败 |
(?: |
开始一个非捕获分组,仅用于将后续的位宽部分组合在一起并设为可选;此分组本身不捕获文本,也不影响后面是否有空格 |
(\[[^\]]+\]) |
捕获组1:匹配方括号及其内部内容(如[31:0]);此原子后面若紧跟\s+则需要有空白,若后面是)则不需要;此处后面是\s+,所以位宽后面必须有空白 |
\s+ |
匹配至少一个空白字符,要求位宽(如果存在)后面必须紧跟空白;若位宽后面无空白(如直接跟端口名),则此\s+匹配失败,导致整个位宽部分无法匹配 |
)? |
结束非捕获分组,?表示整个位宽部分(包括位宽和后面的空白)可以出现0次或1次;若位宽不存在,则直接跳过,不影响后面的端口名匹配 |
(\w+) |
捕获组2:匹配端口名;后面有无空格不影响本捕获(因为它是最后一个元素),但若端口名后面有非单词字符(如逗号或分号),\w+会在单词边界处停止,不会消耗那些字符 |
关键点说明(原内容未改动):
- 位宽部分的可选性是通过
(?:...)?实现的,其中\s+被包含在内,所以如果位宽存在,它后面必须有空白;如果位宽不存在,则不需要空白。 - 这样设计可以同时匹配
input wire clk和input wire [31:0] clk两种情况。
4. pattern4 = r'\binput\s+\w+\s+(\w+)(?:\s*,\s*(\w+))*'
这个模式试图匹配一行中多个用逗号分隔的端口名,例如:input wire clk, rst, en
| 符号序列 | 解释 |
|---|---|
\binput\s+\w+\s+ |
匹配 input wire |
(\w+) |
捕获组1:第一个端口名 |
(?: |
开始非捕获分组(用于重复) |
\s*,\s* |
匹配逗号,两边可有任意空白 |
(\w+) |
捕获组2:后续的端口名 |
)* |
非捕获分组整体可以重复零次或多次 |
问题:findall 只返回最后一个重复捕获组的值(因为正则引擎在重复时只会保留最后一轮捕获的内容)。更可靠的做法是先用 search 提取出 input wire 后面的整个端口列表字符串,再用 split 分割。
三、其他常见但未出现在这些模式中的符号(补充)
| 符号 | 名称 | 作用 |
|---|---|---|
^ |
行首锚点 | 匹配字符串的开始(或多行模式下的行首) |
$ |
行尾锚点 | 匹配字符串的结束(或多行模式下的行尾) |
. |
通配符 | 匹配除换行符外的任意单个字符(默认) |
*? +? ?? |
懒惰量词 | 尽可能少地匹配 |
{n} {n,} {n,m} |
精确次数量词 | 指定重复次数 |
(?=...) |
正向前瞻 | 要求后面匹配但不消耗字符 |
(?!...) |
负向前瞻 | 要求后面不匹配 |
(?<=...) |
正向后顾 | 要求前面匹配 |
(?<!...) |
负向后顾 | 要求前面不匹配 |
\1 \2 |
反向引用 | 引用前面捕获组的内容 |
总结
你列出的这些模式已经覆盖了 Verilog 端口解析中最常用的正则技巧:
\b确保单词独立\s+处理空白\w+匹配标识符\[[^\]]+\]匹配方括号包围的位宽(?:...)非捕获分组用于可选或重复?使整个位宽部分可选*重复逗号分隔的端口列表
理解这些符号的作用后,你就能自如地编写或修改正则表达式来适应不同的 Verilog 代码风格了。
浙公网安备 33010602011771号