如何用Perl脚本匹配两个文件 筛选域名精确匹配的邮箱地址
问题排查
代码无法输出正确结果,核心问题如下:
- 正则匹配逻辑存在缺陷:域名中的
.是正则通配符,可匹配任意单个字符,易引发非预期匹配;同时嵌套循环遍历域名的写法在域名量大时性能极差 - 存在无效逻辑:给文件路径字符串赋值时附带的
or die判断完全无效,只有open操作的返回值才能判断文件是否可访问 - 无异常字符清理逻辑:未处理文件行首尾可能存在的空格、Windows换行符
\r、空行,极易导致匹配失效 - 文件句柄写法不规范:使用裸字文件句柄
MATCH,存在跨作用域污染风险
修正代码
#!/usr/bin/perl use strict; use warnings; use feature 'say'; # 按实际情况修改三个文件的路径,注意不要把域名文件和邮箱文件搞反 my $domain_file = "/home/user/domain_file"; my $email_file = "/home/user/email_address_file"; my $output_file = "matching_domain"; # 读取所有合法域名存入哈希,查询时间复杂度O(1) my %valid_domain; open(my $dom_fh, '<', $domain_file) or die "打开域名文件失败 '$domain_file':$!\n"; while(my $dom = <$dom_fh>) { # 清除首尾所有空白字符(换行、回车、空格、制表符),跳过空行 $dom =~ s/^\s+|\s+$//g; next unless length $dom; $valid_domain{$dom} = 1; } close $dom_fh; # 遍历邮箱文件做精确匹配 open(my $email_fh, '<', $email_file) or die "打开邮箱文件失败 '$email_file':$!\n"; open(my $out_fh, '>', $output_file) or die "写入输出文件失败 '$output_file':$!\n"; while(my $email = <$email_fh>) { $email =~ s/^\s+|\s+$//g; next unless length $email; # 按@分割邮箱,直接取域名部分做精确相等判断,完全规避正则匹配的边界问题 my @email_parts = split /\@/, $email; if (@email_parts == 2 && exists $valid_domain{$email_parts[1]}) { say $out_fh $email; } } close $email_fh; close $out_fh;
逻辑说明
- 放弃正则嵌套匹配方案,改用哈希存储合法域名,匹配性能随域名数量提升的优势非常明显
- 直接通过
split分割邮箱取@后的域名部分做哈希查询,属于严格精确匹配,不会出现gmail.com1、1gmail.com.au、yahooo.com这类误判、漏判情况,也不需要处理正则元字符转义问题 - 增加了通用的空白字符清理逻辑,兼容Windows、Linux格式的文本文件,避免空行、不可见字符导致的匹配失败
- 所有文件操作均采用三参数open+词法文件句柄的现代Perl写法,错误提示明确,稳定性更高
测试验证
用提供的测试文件运行代码,输出文件内容与预期完全一致:
abc@gmail.com abc@yahoo.com
内容的提问来源于stack exchange,提问作者Pankaj Kumar
相关产品推荐
相关产品推荐

