Perl脚本无法提取含多个成员的完整Group文本块求助
问题描述
我需要从文本文件中提取符合特定格式的信息块用于后续处理,目标块格式如下:
Group NAME Description DESCRIPTION Group member MEMBER
所有Group都包含成员,Description是可选字段,成员数量可以是一个或多个,成员名可以是名称或数字。
我写了下面的Perl脚本:
#!/usr/bin/perl use warnings 'all'; use strict; use feature qw(say); my $path="input.txt"; open my $fh, "<", $path or die "Can't open $path: $!"; #local $/; my $accumulated_text = ''; while (my $line = <$fh>) { $accumulated_text .= $line; #Match against accumulated text if ($accumulated_text =~ /group.*\s*(description.*\s*)?\s*(member.*\s*)+/) { say $&; $accumulated_text = ''; } } close $fh;
但这个脚本只能提取一个Group成员,没法提取全部成员。试过用{1,}替代+结果一样,用{2,}这类则只提取指定数量的成员。请问怎么修改才能提取包含所有成员的完整Group块?期望输出是包含所有成员的完整Group信息块。
解决方案
问题出在正则匹配逻辑和文本累积的终止条件上:当前正则会在匹配到第一个member行后就触发匹配,不会等待后续成员行;另外(member.*\s*)+虽然理论上支持多次匹配,但因为没有明确的块终止标记,导致匹配提前结束。可以从以下两个方向修改:
1. 按段落读取+精准匹配(适用于Group块用空白行分隔的场景)
如果你的输入文件中,每个Group块之间用空白行分隔,可以直接用Perl的段落模式读取,再匹配完整块:
#!/usr/bin/perl use warnings 'all'; use strict; use feature qw(say); my $path = "input.txt"; open my $fh, "<", $path or die "Can't open $path: $!"; local $/ = ""; # 开启段落模式,按空白行分隔读取内容块 while (my $block = <$fh>) { # 匹配包含Group开头、可选Description、至少一个成员的完整块 if ($block =~ /^Group\s+\S+.*?(?:Description\s+.*?)?(?:Group member\s+.+)+/is) { print $&; print "\n" unless $& =~ /\n\z/; # 保证块末尾有换行,避免格式混乱 } } close $fh;
2. 基于下一个Group作为终止标记(适用于无空白行分隔的场景)
如果Group块之间没有空白行,而是以下一个Group行作为结束标记,可以用正向预查来限定匹配范围:
#!/usr/bin/perl use warnings 'all'; use strict; use feature qw(say); my $path = "input.txt"; open my $fh, "<", $path or die "Can't open $path: $!"; local $/; # 一次性读取整个文件 my $content = <$fh>; # 匹配所有完整的Group块,直到下一个Group或文件末尾 while ($content =~ /Group\s+\S+.*?(?=Group|\z)/isg) { my $group_block = $&; # 过滤掉没有成员的无效块(题目要求所有Group都有成员) if ($group_block =~ /Group member\s+.+/s) { print $group_block; print "\n" unless $group_block =~ /\n\z/; } } close $fh;
关键修改说明
- 段落模式
local $/ = "":自动将空白行分隔的内容作为独立块读取,刚好对应单个Group的范围。 - 正则修饰符
/is:i忽略大小写(适配输入中Group、Description等关键词大小写不固定的情况);s让.匹配换行符,确保跨多行匹配完整块。 - 正向预查
(?=Group|\z):指定匹配的终止边界,要么是下一个Group开头,要么是文件末尾,保证捕获完整的当前Group块。
内容的提问来源于stack exchange,提问作者mmurro
相关产品推荐
相关产品推荐

