Perl Regex 测试数组是否统一
Perl Regex to test if array is uniform
我有一段代码无法正常工作,我也不知道为什么。
这可能是一个正则表达式问题,但据我所知它应该可以工作。
我有一个包含 <typenumber>:<KitName>
的数组,例如 2:K1663
我想将此数组中每个条目的 KitName
与第一个条目的 KitName
匹配。为此,我有一个正则表达式,它应该 return 冒号 :
之后的所有内容。然后我使用 if
将当前条目 $_
与第一个条目 $KitHit[0]
.
进行比较
然后,如果有任何不匹配,$booly
将被设置为 1 并打印所有条目。
然而,即使套件完全相同,我仍然打印了参赛作品。
我加了个print "A"
或者print "B"
,看看什么时候匹配码,什么时候不匹配码是运行。 returns B A B A B A B A B
完全不考虑我的数据。
谁能告诉我哪里出了问题?我怎么都弄不明白
my @KitHold;
my $booly = 0;
open( $outputfile_fh, ">>", $outputfile ) or die "Could not open file '$outputfile' $!";
foreach ( (), @KitHit ) {
my $KitHelp;
if ( ( $_ =~ /(?<=:)\w+/g ) eq ( $KitHit[0] =~ /(?<=:)\w+/g ) ) {
$KitHelp = $separator[] . "\[$categories[]\]:" . $_ . "\n" if $_ =~ /(\d+)/;
push (@KitHold,$KitHelp);
print "\nA;
}
else {
$KitHelp = $separator[] . "\[$categories[]\]:" . $_ . "\n" if $_ =~ /(\d+)/;
push( @KitHold, $KitHelp );
$booly = 1;
print "\nB";
}
}
if ( $booly == 1 ) {
print {$outputfile_fh} "\n\nKits not uniform:\n@KitHold";
}
close $outputfile_fh;
示例数据:
@KitHit
不匹配:
2:K1663
3:K1675
4:K1663
5:K1663
6:K1663
7:K1663
8:K1675
13:K1675
14:K1675
@KitHit
统一条目:
2:K1663
3:K1663
4:K1663
5:K1663
6:K1663
7:K1663
8:K1663
13:K1663
14:K1663
我还应该提到,Kit 名称最终可能不仅仅包含一个 K 和 4 个数字,因此我的正则表达式会查看冒号后的所有内容。
为什么不使用仅使用正则表达式的解决方案来实现结果?
\A\s*(?>[^\s:]+:(?(1)|(\S+))\s*)+\z
Live demo(不匹配)
Live demo(不匹配)
您可以尝试使用以下方法将每个值与第一个值匹配。
比如说,第一个值是:
K1663
然后您可以遍历其余索引并应用此正则表达式来确定是否匹配。如果匹配,您可以打印它。
use strict;
my $regex = qr/^(\d+):(?!K1663$)(.*)$/mp;
my $str = '3:K1675';
# your loop goes here : where each $str contains the current index value
if( $str =~ /$regex/g )
print " \n";
因此,如果我没看错的话 - 您正在尝试检查所有 "K" 数字是否相同。
我实际上建议 "magic regex" 不是这里的解决方案 - 它是可行的,但不可避免地很难遵循,并且以后很难修改。
相反,我会说您的数据非常适合插入 perl 中的 hash
,因为...好吧,它 是 键值对,并且这就是哈希的用途。
考虑到这一点,我会这样处理:
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
#read it into a hash
my %data = map { /(\d+):(\w+)/ } <>;
# <> is the magic file handle, that reads 'STDIN'
#or files specified to command line.
#you can do the same with any FH that you've opened though.
#for debug
print Dumper \%data;
#count values.
my %count_of;
$count_of{$_}++ for values %data;
#for debug
print Dumper \%count_of;
#if there's more than one key here, we
#have a mismatch
if ( keys %count_of > 1 ) {
print "Mismatch spotted:\n";
foreach my $key ( sort { $a <=> $b} keys %data ) {
print "$key:$data{$key}\n";
}
}
我在这里假设您可以从文件中读入。如果这不是一个有效的假设,那么您可以使用 @KitHit
和 map:
做同样的事情
my %data = map { /(\d+):(\w+)/ } @KitHit;
并做同样的事情。
你的测试
if ( ( $_ =~ /(?<=:)\w+/g ) eq ( $KitHit[0] =~ /(?<=:)\w+/g ) ) {
正在比较两个正则表达式模式匹配的结果。这些结果是字符串是否与模式匹配的布尔指示
您正在测试数组中的值是否包含冒号 :
后跟至少一个 "word" 字符。因为他们都这样做,所以两个匹配的结果将始终为 1。您的比较比较 '1' eq '1'
并且总是导致 true
您的代码还有许多其他问题
您应该显示一个 minimal, complete and verifiable example 以便我们可以自己尝试您的代码
你必须在你写的每一个 Perl 程序的顶部 use strict
和 use warnings 'all'
,并且用 my
声明每个变量尽可能接近它的第一个使用点
大多数 Perl 程序员更熟悉用小写字母、数字和下划线命名的词法变量。避免大写首字母尤为重要。所以 @KitHit
应该是 @kit_hit
您在程序开始时打开输出文件,但直到结束才写入。你是不是想为 appending 打开它?
行foreach ( (), @KitHit ) {
中的()
无效,应删除
您在 if
的两个分支中以相同的方式计算 $KitHelp
并推入 @KitHold
。这些应该在 if
之前或之后单独完成一次
您应该使用变量插值来构建字符串,而不是连接运算符 .
。另请注意,方括号不需要在双引号内转义,因此
$KitHelp = $separator[] . "\[$categories[]\]:" . $_ . "\n"
可以写成
$KitHelp = "$separator[][$categories[]]:$_\n"
你的标志变量 $booly
应该有一个更有意义的名字,比如 $mismatch
你没有显示 @separator
或 @categories
的内容所以我无法正确测试这段代码,但它看起来是正确的并且可以编译
use strict;
use warnings 'all';
my @hit_hold;
my (@separator, @categories); # Need initialising
my @kit_hit = qw/
2:K1663
3:K1675
4:K1663
5:K1663
6:K1663
7:K1663
8:K1675
13:K1675
14:K1675
/;
my $mismatch;
my ($output_file) = @ARGV; # Take output file name from command line
die unless my ($n0, $key0) = $kit_hit[0] =~ /^(\d+):(.+)/;
for ( @kit_hit ) {
next unless my ($n, $key) = /^(\d+):(.+)/;
push @hit_hold, "$separator[$n][$categories[]]:$_\n";
if ( $key eq $key0 ) {
print "\nA";
}
else {
$mismatch = 1;
print "\nB";
}
}
if ( $mismatch ) {
open my $out_fh, '>', $output_file or die qq{Could not open "$output_file" for output: $!};
my $old_fh = select $out_fh;
print "\n\n";
print "Kits not uniform:\n";
print "$_\n" for @hit_hold;
close $out_fh;
select $old_fh;
}
我有一段代码无法正常工作,我也不知道为什么。 这可能是一个正则表达式问题,但据我所知它应该可以工作。
我有一个包含 <typenumber>:<KitName>
的数组,例如 2:K1663
我想将此数组中每个条目的 KitName
与第一个条目的 KitName
匹配。为此,我有一个正则表达式,它应该 return 冒号 :
之后的所有内容。然后我使用 if
将当前条目 $_
与第一个条目 $KitHit[0]
.
然后,如果有任何不匹配,$booly
将被设置为 1 并打印所有条目。
然而,即使套件完全相同,我仍然打印了参赛作品。
我加了个print "A"
或者print "B"
,看看什么时候匹配码,什么时候不匹配码是运行。 returns B A B A B A B A B
完全不考虑我的数据。
谁能告诉我哪里出了问题?我怎么都弄不明白
my @KitHold;
my $booly = 0;
open( $outputfile_fh, ">>", $outputfile ) or die "Could not open file '$outputfile' $!";
foreach ( (), @KitHit ) {
my $KitHelp;
if ( ( $_ =~ /(?<=:)\w+/g ) eq ( $KitHit[0] =~ /(?<=:)\w+/g ) ) {
$KitHelp = $separator[] . "\[$categories[]\]:" . $_ . "\n" if $_ =~ /(\d+)/;
push (@KitHold,$KitHelp);
print "\nA;
}
else {
$KitHelp = $separator[] . "\[$categories[]\]:" . $_ . "\n" if $_ =~ /(\d+)/;
push( @KitHold, $KitHelp );
$booly = 1;
print "\nB";
}
}
if ( $booly == 1 ) {
print {$outputfile_fh} "\n\nKits not uniform:\n@KitHold";
}
close $outputfile_fh;
示例数据:
@KitHit
不匹配:
2:K1663
3:K1675
4:K1663
5:K1663
6:K1663
7:K1663
8:K1675
13:K1675
14:K1675
@KitHit
统一条目:
2:K1663
3:K1663
4:K1663
5:K1663
6:K1663
7:K1663
8:K1663
13:K1663
14:K1663
我还应该提到,Kit 名称最终可能不仅仅包含一个 K 和 4 个数字,因此我的正则表达式会查看冒号后的所有内容。
为什么不使用仅使用正则表达式的解决方案来实现结果?
\A\s*(?>[^\s:]+:(?(1)|(\S+))\s*)+\z
Live demo(不匹配)
Live demo(不匹配)
您可以尝试使用以下方法将每个值与第一个值匹配。
比如说,第一个值是:
K1663
然后您可以遍历其余索引并应用此正则表达式来确定是否匹配。如果匹配,您可以打印它。
use strict;
my $regex = qr/^(\d+):(?!K1663$)(.*)$/mp;
my $str = '3:K1675';
# your loop goes here : where each $str contains the current index value
if( $str =~ /$regex/g )
print " \n";
因此,如果我没看错的话 - 您正在尝试检查所有 "K" 数字是否相同。
我实际上建议 "magic regex" 不是这里的解决方案 - 它是可行的,但不可避免地很难遵循,并且以后很难修改。
相反,我会说您的数据非常适合插入 perl 中的 hash
,因为...好吧,它 是 键值对,并且这就是哈希的用途。
考虑到这一点,我会这样处理:
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
#read it into a hash
my %data = map { /(\d+):(\w+)/ } <>;
# <> is the magic file handle, that reads 'STDIN'
#or files specified to command line.
#you can do the same with any FH that you've opened though.
#for debug
print Dumper \%data;
#count values.
my %count_of;
$count_of{$_}++ for values %data;
#for debug
print Dumper \%count_of;
#if there's more than one key here, we
#have a mismatch
if ( keys %count_of > 1 ) {
print "Mismatch spotted:\n";
foreach my $key ( sort { $a <=> $b} keys %data ) {
print "$key:$data{$key}\n";
}
}
我在这里假设您可以从文件中读入。如果这不是一个有效的假设,那么您可以使用 @KitHit
和 map:
my %data = map { /(\d+):(\w+)/ } @KitHit;
并做同样的事情。
你的测试
if ( ( $_ =~ /(?<=:)\w+/g ) eq ( $KitHit[0] =~ /(?<=:)\w+/g ) ) {
正在比较两个正则表达式模式匹配的结果。这些结果是字符串是否与模式匹配的布尔指示
您正在测试数组中的值是否包含冒号 :
后跟至少一个 "word" 字符。因为他们都这样做,所以两个匹配的结果将始终为 1。您的比较比较 '1' eq '1'
并且总是导致 true
您的代码还有许多其他问题
您应该显示一个 minimal, complete and verifiable example 以便我们可以自己尝试您的代码
你必须在你写的每一个 Perl 程序的顶部
use strict
和use warnings 'all'
,并且用my
声明每个变量尽可能接近它的第一个使用点大多数 Perl 程序员更熟悉用小写字母、数字和下划线命名的词法变量。避免大写首字母尤为重要。所以
@KitHit
应该是@kit_hit
您在程序开始时打开输出文件,但直到结束才写入。你是不是想为 appending 打开它?
行
foreach ( (), @KitHit ) {
中的()
无效,应删除您在
if
的两个分支中以相同的方式计算$KitHelp
并推入@KitHold
。这些应该在if
之前或之后单独完成一次
您应该使用变量插值来构建字符串,而不是连接运算符
.
。另请注意,方括号不需要在双引号内转义,因此$KitHelp = $separator[] . "\[$categories[]\]:" . $_ . "\n"
可以写成
$KitHelp = "$separator[][$categories[]]:$_\n"
你的标志变量
$booly
应该有一个更有意义的名字,比如$mismatch
你没有显示 @separator
或 @categories
的内容所以我无法正确测试这段代码,但它看起来是正确的并且可以编译
use strict;
use warnings 'all';
my @hit_hold;
my (@separator, @categories); # Need initialising
my @kit_hit = qw/
2:K1663
3:K1675
4:K1663
5:K1663
6:K1663
7:K1663
8:K1675
13:K1675
14:K1675
/;
my $mismatch;
my ($output_file) = @ARGV; # Take output file name from command line
die unless my ($n0, $key0) = $kit_hit[0] =~ /^(\d+):(.+)/;
for ( @kit_hit ) {
next unless my ($n, $key) = /^(\d+):(.+)/;
push @hit_hold, "$separator[$n][$categories[]]:$_\n";
if ( $key eq $key0 ) {
print "\nA";
}
else {
$mismatch = 1;
print "\nB";
}
}
if ( $mismatch ) {
open my $out_fh, '>', $output_file or die qq{Could not open "$output_file" for output: $!};
my $old_fh = select $out_fh;
print "\n\n";
print "Kits not uniform:\n";
print "$_\n" for @hit_hold;
close $out_fh;
select $old_fh;
}