【问题标题】:Comparing tokens of string with tokens of array of strings将字符串标记与字符串数组标记进行比较
【发布时间】:2015-10-22 06:03:08
【问题描述】:

我有一个包含空格分隔标记列表的字符串。

my $string = "--configure-option1 --configure-option2 --configure-option3 --configure-option4";

我有一个类似字符串的数组。

my @array = (
   "--configure-option20",
   "--configure-option2 --configure-option5",
   "--configure-option10 --configure-option11",
   "--configure-option15 --configure-option22 --configure-option27",
);

我想确定$string 中的任何标记是否也在@array 中的一个字符串中找到。例如,由于$string 和@987654326,上述值的结果都是正确的@ 包含令牌--configure-option2

【问题讨论】:

  • 这似乎也是一个 XY 问题。分享一些关于你在做什么以及为什么做的见解。
  • @ikegami 因为如果他正在解析一个字符串,很高兴知道这个字符串实际上是什么样子的?
  • 测试“string1 的任何子串匹配 string2 的任何子串”可以简化为 1 (true),因为 "" eq "" 对任何 string1 和 string2 都是 true。
  • 请您将您的数据示例更改为可编译的 Perl。例如Data::Dumper 的输出
  • @Kaleb Perl 字符串不会被\0 终止,并且\0 不是空格(同样,每个字符串本身就是一个字符串)。

标签: arrays regex perl substring


【解决方案1】:
my $alt = join '|', map quotemeta, split ' ', $string;
my $re = qr/(?<!\S)(?:$alt)(?!\S)/;

my $match = grep /$re/, @array;

为了加快速度:

my $match = join(' ', @array) =~ /$re/;

为了加快速度并节省内存:

my $match = 0
for (@array) {
   if (/$re/) {
      $match = 1;
      last;
   }
}

【讨论】:

  • 不,事实上我不需要从 [--configure-option2 --configure-option5] 和 [--configure-option10 --configure- 匹配这个“--configure-option2”选项2]
  • 你也可以直接写my $escaped_chars = quotemeta($string1),让正则引擎来整理
  • @Borodin 感谢您提供一些建设性的建议。如果可行,我会尝试并投票。
  • @Kaleb 仅仅因为你不明白他们在说什么或在问什么就要求他们停止帮助并不是一个好主意。尝试回答问题并提供相关反馈,您的问题将得到更快的回答。有了相关信息,一个问题通常可以在几分钟内得到解答。在OP不懂问的情况下,答案会延迟,有时永远不会来。
  • 更新了我的答案以匹配问题的最新版本。
【解决方案2】:

如果我猜对了你的数据格式,我认为这可以解决你的问题

它将@failures 数组转换为一个散列,其中包含所有不同的选项,如果它们出现则应该导致拒绝。然后它通过@array(你的名字,不是我的!)运行并使用grep检查%failures哈希中是否出现任何组成选项,并打印结果

如果速度是个问题,那么您可能希望将 grep 替换为来自 List::MoreUtilsany

use strict;
use warnings;
use 5.010;

my @array = (
    '--configure-option1 --configure-option2 --configure-option3 --configure-option4',
    '--configure-option3 --configure-option4 --configure-option12',
);

my @failures = (
    '--configure-option20',
    '--configure-option2 --configure-option5',
    '--configure-option10 --configure-option11',
    '--configure-option15 --configure-option22 --configure-option27',
);

my %failures;
$failures{$_} = 1 for map split, @failures;

for my $options ( @array ) {
    my $reject = grep { $failures{$_} } split ' ', $options;
    say $options, '  ', $reject ? 'FAIL' : 'PASS';
}

输出

--configure-option1 --configure-option2 --configure-option3 --configure-option4  FAIL
--configure-option3 --configure-option4 --configure-option12  PASS

【讨论】:

  • 虽然 anygrep 好,但仍然是 O(N)。如果你想优化这个版本,你会使用我之前的答案。实际上,您应该构建一个正则表达式而不是拆分。
【解决方案3】:

您的问题还不清楚。根据我在字里行间的阅读,我想出了这个:

#!/usr/bin/env perl

use strict;
use warnings;

use Set::CrossProduct;

my $x = '[--configure-option1 --configure-option2 --configure-option3 --configure-option4]';

my $y = '[--configure-option20][--configure-option2 --configure-option5][--configure-option10 --configure-option11][--configure-option15 --configure-option22 --configure-option27]';

my $pat = qr/([a-z0-9-]+)/;

my @x = ($x =~ /$pat/g);
my @y = ($y =~ /$pat/g);

my $it = Set::CrossProduct->new([\@x, \@y]);
while (my $el = $it->get) {
    if ($el->[0] eq $el->[1]) {
        printf "'%s' appears in both\n", $el->[0];
    }
}

输出:

C:\...\Temp> perl tt.pl
'--configure-option2' 出现在两者中

【讨论】:

    【解决方案4】:
        #!/usr/bin/perl
    
    
    my @pairs = (
        '--configure-option1 --configure-option2 --configure-option3 --configure-option4',
        '--configure-option3 --configure-option4 --configure-option12',
    );
    
    my @failures = (
        '--configure-option20',
        '--configure-option2 --configure-option5',
        '--configure-option10 --configure-option11',
        '--configure-option15 --configure-option22 --configure-option27',
    );
    
    $all = 0;
    $size = $#pairs + 1;
    my $string1;
    my $string2;
    
    while ($all < $size) {
    ##... Other code happening here
    ## Begin test case
    ####################################################
    
            # loop through the existing failure cases. Logic here is that
            # the failures array will always be < the build array.
            # (the full build array has thousands of options while the
            # failures array can not possibly grow larger than that and
            # ideally will be much smaller than that.
            foreach $string1 (@failures) {
    
                $string2 = $pairs[$all];
    
                # get string1 from the Failures array and parse it up into the
                # @compare1 array
                # get string2 from the current configure option and parse it into
                # @compare2 array
    
                my @compare1 = split(' ', $string1);
                my @compare2 = split(' ', $string2);
    
                # loop through both arrays storing each element in var1 and var2
                # for comparing
                foreach my $var1 (@compare1) {
                    foreach my $var2 (@compare2) {
    
                        #see if var1 and var2 match
                        if ($var1 eq $var2) {
                            print "ALERT!!!!\n";
                            print "string1 is: \"$string1\"\n";
                            print "string2 is: \"$string2\"\n\n";
                            print "found match string1 contains $var1 and string2 contains $var2\n\n";
                            $reject = 1;
                        }
                    }
                }
            }
    
            if ($reject eq 1) {
                print "\n$string2\n";
                print "didn't run this test because it's been rejected\n\n";
    
                # reset the reject flag
                $reject = 0;
            }
            else {
                print "\n$string2\n";
                print "This test did run\n\n";
            }
    
            $all = $all + 1;
    ####################################################
    ## End test case
    ##... Rest of script
    }
    

    运行输出:

    ALERT!!!!
    string1 is: "--configure-option2 --configure-option5"
    string2 is: "--configure-option1 --configure-option2 --configure-option3 --configure-option4"
    
    found match string1 contains --configure-option2 and string2 contains --configure-option2
    
    
    --configure-option1 --configure-option2 --configure-option3 --configure-option4
    didn't run this test because it's been rejected
    
    
    --configure-option3 --configure-option4 --configure-option12
    This test did run
    

    【讨论】:

    • 所提供的解决方案均未按最终脚本的预期运行。思南你的很接近,但我无法让它很好地工作。谢谢你的提交。 @ikegami 你的努力获得了第一场比赛,但是之后的一切也会报告一场比赛,即使没有比赛。这就是我最终自己解决的问题。它有效,但可能远非最佳。如果您有任何优化建议,请提供。问候,卡莱布
    • @ikegami 另外感谢您清理我的问题。对于我最初在这个问题上缺乏明确性,我深表歉意。我很难用语言来表达我的想法。今后我会努力在这方面做得更好。
    • Re“你已经努力获得第一场比赛,但是之后的一切都会报告一场比赛,即使没有比赛。”这绝对没有意义。根据要求,它仅检查是否存在匹配项。它没有得到任何匹配,所以它不可能让第一个匹配正确而后面的匹配错误。
    • Re“我很难用文字表达”,那就不要用文字了。如果您提供了所有必要的信息(您的输入、您的代码、您想要的输出和您获得的输出),那么进一步的描述几乎是不必要的。
    • Re“如果您有任何优化建议,请贡献。”,您的解决方案扩展性非常糟糕。我已经为提出的问题提供了优化的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-04
    相关资源
    最近更新 更多