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";

Regex Demo

Demo Impl

因此,如果我没看错的话 - 您正在尝试检查所有 "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 strictuse 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;
}