Perl 正则表达式 - 在匹配前后获取文本
Perl Regex - Getting Text Before and After Match
我正在逐行解析制表符分隔的文件:
Root rootrank 1 Bacteria domain .72 Firmicutes phylum 1 Clostridia class 1 etc.
=
while (my $line = <$fh>) {
chomp($line);
}
在每一行中,我都想捕获特定匹配前后的第一个条目。例如,对于匹配 phylum
,我想捕获条目 Firmicutes
和 1
。对于匹配 domain
,我想捕获条目 Bacteria
和 .72
。我将如何编写正则表达式来执行此操作?
旁注:我不能简单地将一行一行地拆分成一个数组并使用索引,因为有时会丢失一个类别或有额外的类别,这会导致条目移动一个或两个索引。我想避免编写 if 语句块。
您仍然可以拆分输入,然后将单词映射到索引,然后使用与匹配对应的索引来提取相邻单元格:
#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };
my @matches = qw( phylum domain );
while (<>) {
chomp;
my @cells = split /\t/;
my %indices;
@indices{ @cells } = 0 .. $#cells;
for my $match (@matches) {
if (defined( my $index = $indices{$match} )) {
say join "\t", @cells[ $index - 1 .. $index + 1 ];
}
}
}
缺少什么:
- 您应该处理 $index == 0 或 $index == $#cells 的情况。
- 你应该处理一些单词在一行中重复的情况。
您可以简单地使用以下 regex 来捕获匹配词的词 before
和 after
:
(?<LSH>[\w.]+)[\s\t](?<MATCH>.*?)[\s\t](?<RHS>[\w.]+)
你可以这样做:
#!/usr/bin/perl
use Modern::Perl;
my @words = qw(phylum domain);
while(<DATA>) {
chomp;
for my $word (@words) {
my ($before, $after) = $_ =~ /(\S+)(?:\t\Q$word\E\t)(\S+)/i;
say "word: $word\tbefore: $before\tafter: $after";
}
}
__DATA__
Root rootrank 1 Bacteria domain .72 Firmicutes phylum 1 Clostridia class 1 etc.
输出:
word: phylum before: Firmicutes after: 1
word: domain before: Bacteria after: .72
my $file = "file2.txt";
open my $fh, '<', $file or die "Unable to Open the file $file for reading: $!\n";
while (my $line = <$fh>) {
chomp $line;
while ($line =~ /(\w+)\s+(\w+)\s+(\.?\d+)/g) {
my ($before, $match, $after) = (, , );
print "Before: $before Match: $match After: $after\n";
}
}
我正在逐行解析制表符分隔的文件:
Root rootrank 1 Bacteria domain .72 Firmicutes phylum 1 Clostridia class 1 etc.
=
while (my $line = <$fh>) {
chomp($line);
}
在每一行中,我都想捕获特定匹配前后的第一个条目。例如,对于匹配 phylum
,我想捕获条目 Firmicutes
和 1
。对于匹配 domain
,我想捕获条目 Bacteria
和 .72
。我将如何编写正则表达式来执行此操作?
旁注:我不能简单地将一行一行地拆分成一个数组并使用索引,因为有时会丢失一个类别或有额外的类别,这会导致条目移动一个或两个索引。我想避免编写 if 语句块。
您仍然可以拆分输入,然后将单词映射到索引,然后使用与匹配对应的索引来提取相邻单元格:
#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };
my @matches = qw( phylum domain );
while (<>) {
chomp;
my @cells = split /\t/;
my %indices;
@indices{ @cells } = 0 .. $#cells;
for my $match (@matches) {
if (defined( my $index = $indices{$match} )) {
say join "\t", @cells[ $index - 1 .. $index + 1 ];
}
}
}
缺少什么:
- 您应该处理 $index == 0 或 $index == $#cells 的情况。
- 你应该处理一些单词在一行中重复的情况。
您可以简单地使用以下 regex 来捕获匹配词的词 before
和 after
:
(?<LSH>[\w.]+)[\s\t](?<MATCH>.*?)[\s\t](?<RHS>[\w.]+)
你可以这样做:
#!/usr/bin/perl
use Modern::Perl;
my @words = qw(phylum domain);
while(<DATA>) {
chomp;
for my $word (@words) {
my ($before, $after) = $_ =~ /(\S+)(?:\t\Q$word\E\t)(\S+)/i;
say "word: $word\tbefore: $before\tafter: $after";
}
}
__DATA__
Root rootrank 1 Bacteria domain .72 Firmicutes phylum 1 Clostridia class 1 etc.
输出:
word: phylum before: Firmicutes after: 1
word: domain before: Bacteria after: .72
my $file = "file2.txt";
open my $fh, '<', $file or die "Unable to Open the file $file for reading: $!\n";
while (my $line = <$fh>) {
chomp $line;
while ($line =~ /(\w+)\s+(\w+)\s+(\.?\d+)/g) {
my ($before, $match, $after) = (, , );
print "Before: $before Match: $match After: $after\n";
}
}