Perl中如何嵌入正则变量至其他正则并结合命名捕获组?
Perl正则变量嵌入其他正则的问题解决
你尝试将预定义的正则模式$portR嵌入另一个正则表达式时遇到了变量未初始化的错误,原代码如下:
#!/usr/bin/perl use strict; use warnings; use Getopt::Long; Getopt::Long::Configure("no_ignore_case"); my($host, $port); my $getoptret = GetOptions( "H|host:s" => sub { setHost($_[1]); }, "p|port:i" => \$port ); #port: 0-65535 59999 64999 65499 65529 65535 #my $portPat= qr/[0-5][0-9]{,4}|6[0-4][0-9]{,3}|65[0-4][0-9]{,2}|655[0-2][0-9]|6553[0-5]/; #my $portR= qr/(((([0-5]?[0-9]?|6[0-4])[0-9]?|65[0-4])[0-9]?|655[0-2])[0-9]?|6553[0-5]?)/; my $portR= qr/[0-9]/; #dummyRange sub setHost{ #host: (https://)site.com(:port) if ($_[0] =~ /^(?<uriS>(?:https?):\/\/)?(?<hmain>(?<okC>[a-zA-Z0-9-_]+)(\.(?&okC))+?)(?<hport>\:(\${portR}))?$/) { $host= $+{'uriS'}.$+{'hmain'}; if ($+{'hport'}){ $port= substr($+{'hport'}, 1); }; print "|".$host.'|'.$port."|\n"; }else{ printf "ERROR: no valid host: %s\n", $_[0]; } }
运行后返回错误:
Use of uninitialized value $portR in regexp compilation at xyz.pl
你曾尝试调整捕获组但仍失败,且需要保留捕获分组,下面是两种正确的正则嵌入方法:
方法1:直接引用预编译正则变量
Perl支持在正则表达式中直接使用qr//生成的预编译正则对象,不需要用字符串插值语法${}。修改setHost函数中的正则部分即可:
sub setHost{ #host: (https://)site.com(:port) if ($_[0] =~ /^(?<uriS>(?:https?):\/\/)?(?<hmain>(?<okC>[a-zA-Z0-9-_]+)(\.(?&okC))+?)(?<hport>\:($portR))?$/) { $host= $+{'uriS'}.$+{'hmain'}; if ($+{'hport'}){ $port= substr($+{'hport'}, 1); }; print "|".$host.'|'.$port."|\n"; }else{ printf "ERROR: no valid host: %s\n", $_[0]; } }
这里直接把\${portR}改成$portR,Perl会自动将预编译的正则整合到当前表达式中,既保留了捕获分组,也避免了变量未初始化的警告。
方法2:字符串拼接后编译为正则
如果需要动态组合多个正则片段,可以先拼接成字符串,再用qr//编译成正则对象:
# 提前编译完整正则 my $fullHostRegex = qr/^(?<uriS>(?:https?):\/\/)?(?<hmain>(?<okC>[a-zA-Z0-9-_]+)(\.(?&okC))+?)(?<hport>\:(?:$portR))?$/; sub setHost{ #host: (https://)site.com(:port) if ($_[0] =~ $fullHostRegex) { $host= $+{'uriS'}.$+{'hmain'}; if ($+{'hport'}){ $port= substr($+{'hport'}, 1); }; print "|".$host.'|'.$port."|\n"; }else{ printf "ERROR: no valid host: %s\n", $_[0]; } }
这种方式适合需要动态生成正则的场景,同样能正确保留捕获分组。
错误原因说明
之前使用${portR}会触发字符串插值,但$portR是正则对象,插值时会被转为字符串形式(比如(?^:[0-9])),不仅容易出现转义问题,还会因为正则编译时机的问题导致变量未初始化警告。直接引用正则变量是Perl官方推荐的正确方式,能避免这类问题。
内容的提问来源于stack exchange,提问作者mcaustria
相关产品推荐
相关产品推荐

