如何在Perl脚本中用RegEx提取<ix:hidden>标签间的代码
问题场景
需要提取<ix:hidden>与</ix:hidden>标签之间的代码,目标HTML片段如下:
<ix:hidden> <ix:nonNumeric contextRef="Duration_4_1_2021_To_3_31_2022_IlKaMcQ2N0C41UxW3xo4zg" name="dei:DocumentType" id="Tc_evMsUKdlCEyCZtbxEMZIxg_1_1">DEF 14A</ix:nonNumeric> <ix:nonNumeric contextRef="Duration_4_1_2021_To_3_31_2022_IlKaMcQ2N0C41UxW3xo4zg" name="dei:AmendmentFlag" id="Tc_nHcapE52UUqrWD0pLkbdag_2_1">false</ix:nonNumeric> <ix:nonNumeric contextRef="Duration_4_1_2021_To_3_31_2022_IlKaMcQ2N0C41UxW3xo4zg" name="dei:EntityRegistrantName" id="Tc_ZXMW19KSmk2TfvdhMCMr_A_3_1">Walter Hamscher Co Number One</ix:nonNumeric> <ix:nonNumeric contextRef="Duration_4_1_2021_To_3_31_2022_IlKaMcQ2N0C41UxW3xo4zg" name="dei:EntityCentralIndexKey" id="Tc_MybzAywpbUCU3LEGZc_Ftg_4_1">0000990667</ix:nonNumeric> </ix:hidden>
用户编写的Perl脚本中,正则表达式未匹配到目标内容,原脚本如下:
use strict; use warnings; my @ar_sp; my $string; my @ar_out; # Source File my $src = 'iXBRL-Tagged_tm213138-13_def14a.htm'; # open source file for reading open(FHR, '<', $src); # Destination File my $des = 'output.txt'; # Open new file to write open(FHW, '>', $des); print("Copying content from $src to $des\n"); @ar_sp = <FHR>; # Copy data from one file to another. foreach $string ( @ar_sp ) { if ($string =~ m/<ix:hidden>(.*?)<\/ix:hidden>/) { print "Yes" . "\n"; $string =~ m/<ix:hidden>(.*?)<\/ix:hidden>/; print FHW $string; } } # Closing the filehandles close(FHR); close(FHW); print "File content copied successfully!\n";
问题原因
- 逐行读取导致匹配失败:原脚本按行读取文件,但
<ix:hidden>标签内容跨了多行,单行中不存在完整的<ix:hidden>...</ix:hidden>标签对,正则自然无法匹配。 - 正则未处理换行符:默认情况下,Perl正则中的
.不会匹配换行符,即使标签逻辑上是连续块,.*?也无法覆盖多行内容。 - 输出错误:即使匹配成功,脚本输出的是原行内容,而非捕获到的标签间代码。
修复方案
核心修改点
- 读取整个文件内容,而非逐行读取,确保能获取完整的标签块。
- 给正则添加
/s修饰符,让.匹配换行符,支持跨行匹配。 - 捕获标签间的内容并写入输出文件,而非原字符串。
修正后的脚本
use strict; use warnings; # 文件路径 my $src = 'iXBRL-Tagged_tm213138-13_def14a.htm'; my $des = 'output.txt'; # 读取整个文件内容 open(my $fh_in, '<', $src) or die "无法打开源文件: $!"; local $/; # 取消输入记录分隔符,一次性读取全部内容 my $content = <$fh_in>; close($fh_in); # 提取<ix:hidden>标签间的内容 if ($content =~ m/<ix:hidden>(.*?)<\/ix:hidden>/s) { my $hidden_content = $1; # 写入输出文件 open(my $fh_out, '>', $des) or die "无法打开输出文件: $!"; print $fh_out $hidden_content; close($fh_out); print "标签内容已成功提取到 $des\n"; } else { print "未找到匹配的<ix:hidden>标签\n"; }
关键说明
local $/:临时取消Perl的输入记录分隔符(默认是换行符),这样<$fh_in>会一次性读取整个文件的所有内容。/s修饰符:让正则中的.匹配包括换行符在内的所有字符,确保跨行的标签内容能被完整捕获。- 捕获分组
$1:对应正则中(.*?)匹配到的内容,也就是<ix:hidden>和</ix:hidden>之间的代码。
内容的提问来源于stack exchange,提问作者Chidam Baram
相关产品推荐
相关产品推荐

