加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

在Perl中,如果强制使用foreach循环,如何在字符串中找到匹配的位

发布时间:2020-12-15 23:26:37 所属栏目:大数据 来源:网络整理
导读:我必须使用while循环在较大的字符串中找到匹配字符串的所有位置,并使用foreach循环作为第二种方法.我已经找到了while循环方法,但我坚持使用foreach方法.这是’while’方法: …. my $sequence = 'AACAAATTGAAACAATAAACAGAAACAAAAATGGATGCGATCAAGAAAAAGATGC'.
我必须使用while循环在较大的字符串中找到匹配字符串的所有位置,并使用foreach循环作为第二种方法.我已经找到了while循环方法,但我坚持使用foreach方法.这是’while’方法:

….

my $sequence = 
   'AACAAATTGAAACAATAAACAGAAACAAAAATGGATGCGATCAAGAAAAAGATGC'.
   'AGGCGATGAAAATCGAGAAGGATAACGCTCTCGATCGAGCCGATGCCGCGGAAGA'.
   'AAAAGTACGTCAAATGACGGAAAAGTTGGAACGAATCGAGGAAGAACTACGTGAT'.
   'ACCCAGAAAAAGATGATGCNAACTGAAAATGATTTAGATAAAGCACAGGAAGATT'.
   'TATCTGTTGCAAATACCAACTTGGAAGATAAGGAAAAGAAAGTTCAAGAGGCGGA'.
   'GGCTGAGGTAGCANCCCTGAATCGTCGTATGACACTTCTGGAAGAGGAATTGGAA'.
   'CGAGCTGAGGAACGTTTGAAGATTGCAACGGATAAATTGGAAGAAGCAACACATA'.
   'CAGCTGATGAATCTGAACGTGTTCGCNAGGTTATGGAAA';

my $string = <STDIN>;
chomp $string;

while ($sequence =~ /$string/gi )
{
 printf "Sequence found at position: %dn",pos($sequence)- length($string);
}

这是我的foreach方法:

foreach  ($sequence =~ /$string/gi ) 

 printf "Sequence found at position: %dn",pos($sequence) - length($string); 
}

有人可以告诉我为什么它不能以同样的方式工作吗?
谢谢!

如果我输入“aaca”,我的输出:

Part 1 using a while loop
Sequence found at position: 0
Sequence found at position: 10
Sequence found at position: 17
Sequence found at position: 23
Sequence found at position: 377

Part 2 using a foreach loop
Sequence found at position: -4
Sequence found at position: -4
Sequence found at position: -4
Sequence found at position: -4
Sequence found at position: -4

解决方法

你的问题是上下文.在while循环中,条件位于标量上下文中.在标量上下文中,g模式下的匹配运算符将沿着字符串顺序匹配.因此,在循环中检查pos可以满足您的需求.

在foreach循环中,条件位于列表上下文中.在列表上下文中,g模式下的匹配运算符将返回所有匹配的列表(并且它将在输入循环体之前计算所有匹配). foreach然后逐个将匹配加载到$_中,但是你永远不会使用变量.循环体中的pos没有用,因为它包含匹配结束后的结果.

这里要说的是,如果你想要pos工作,并且你正在使用g修饰符,你应该使用while循环来强制标量上下文并使正则表达式遍历字符串中的匹配.

思南启发我写了几个foreach例子:

>使用拆分分隔符保留模式时,这个是相当简洁的:

my $pos = 0;
foreach (split /($string)/i => $sequence) {
    print "Sequence found at position: $posn" if lc eq lc $string;
    $pos += length;
}

>正则表达式相当于拆分解决方案:

my $pos = 0;
foreach ($sequence =~ /(Q$stringE|(?:(?!Q$stringE).)+)/gi) {
    print "Sequence found at position: $posn" if lc eq lc $string;
    $pos += length;
}

>但这显然是解决您问题的最佳方案:

{package Dumb::Homework;
    sub TIEARRAY {
        bless {
            haystack => $_[1],needle   => $_[2],size     => 2**31-1,pos      => [],}
    }
    sub FETCH {
        my ($self,$index) = @_;
        my ($pos,$needle) = @$self{qw(pos needle)};

        return $$pos[$index] if $index < @$pos;

        while ($index + 1 >= @$pos) {
            unless ($$self{haystack} =~ /Q$needle/gi) {
                $$self{size} = @$pos;
                last
            }
            push @$pos,pos ($$self{haystack}) - length $needle;
        }
        $$pos[$index]
    }
    sub FETCHSIZE {$_[0]{size}}
}

tie my @pos,'Dumb::Homework' => $sequence,$string;

print "Sequence found at position: $_n" foreach @pos; # look how clean it is

它最好的原因是因为其他两个解决方案必须首先处理整个全局匹配,然后才能看到结果.对于可能有问题的大输入(如DNA). Dumb :: Homework包实现了一个数组,每次foreach迭代器请求它时都会懒洋洋地找到下一个位置.它甚至会存储位置,以便您可以再次访问它们而无需重新处理. (事实上??,它看起来超过了请求的匹配,这使得它可以在foreach中正确结束,但仍然比处理整个列表要好得多)>实际上,最好的解决方案仍然是不使用foreach,因为它不是正确的工具.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读