使用正则表达式匹配字符串中连续的字符

3

我不确定如何给这个问题命名,所以继续...

我想要匹配一个较大字符串中的子串。例如:

  • MatchPartOfThisString -> 参考字符串
  • fThisDiff -> 我想要匹配其中连续5个字符的字符串

我可以遍历第一个字符串,从参考字符串中找到最小数量的连续匹配,然后检查这些匹配是否与另一个字符串相匹配:

if(fThisDiff =~ /Match/) {
    do something...;
}
if(fThisDiff =~ /atchP/) {
    do something...;
}
if(fThisDiff =~ /tchPa/) {
    do something...;
}

但我希望以更加优雅的方式来完成,如果有一种方法可以使用一个正则表达式重复解析参考字符串的某些部分,我会更喜欢。我不认为这是可行的,但无论如何我都需要确认。


1
查看“模糊匹配”。例如,请参阅此帖子,其中列出了一些具有示例的模块。 - zdim
3个回答

3

没有一种简单的方法可以使用正则表达式来完成这个任务,但是有一些 CPAN 模块可以帮助构建这样的正则表达式。

use strict;
use warnings;
use String::Substrings 'substrings';
use Data::Munge 'list2re';

my $match_string = 'MatchPartOfThisString';
my $re = list2re substrings $match_string, 5;
my $subject = 'fThisDiff';
if ($subject =~ m/($re)/) {
  print "Matched $1 from $match_string in $subject\n";
}

1
@WetCheerios 两个函数都非常简单且纯Perl,因此您可以从源代码中复制它们(您可以在metacpan上找到它们),只要您遵守许可证/版权。或者,如果允许的话,您可以将模块本地安装捆绑到您的项目中,或者将它们打包到脚本中。 - Grinnz
@WetCherious 为什么不能添加模块?请定义环境变量 PERL5LIB 并使用 cpan 来安装模块-这些模块将会被安装到你指定的 PERL5LIB 变量路径下。 - Polar Bear
@WetCheerios,如果你可以添加一个脚本,那么你也可以添加一个模块。它们之间没有区别。 - ikegami
1
@PolarBear PERL5LIB并不告诉你安装的位置。你必须配置cpanPERL_MM_OPTPERL_MB_OPT,告诉Makefile.PL/Build.PL在其他地方进行安装。 - ikegami
1
@PolarBear 我提到了两个选项。cpanm -l ~/.perl Some::Module 或者在您的环境中激活 local::lib 并将其指向该目录。 - Grinnz
显示剩余4条评论

3
这是一个简单的方法,通过手动使用内置工具来实现。从参考字符串中构建一个正则表达式模式,该模式包含所需长度的子字符串的交替出现。
use warnings;
use strict;
use feature 'say';

sub get_alt_re {
    my ($str, $len) = @_; 
    $len //= 1;            #/
    my @substrings;
    foreach my $beg (0 .. length($str)-$len) {
        push @substrings, substr($str, $beg, $len);
    }
    return '(' .  join('|', map quotemeta, @substrings) . ')';
}   

my $ref    = q(MatchPartOfThisString);
my $target = q(fThisDiff);

my $re = get_alt_re($ref, 5);

my @m = $target =~ /$re/g;
say for @m; 

打印出fThis这一行。

应该使代码更加健壮和通用。然后,它可以很容易地修改为匹配一系列长度(不仅仅是5以上)。此外,它可以使用子任务库(那些重复调用substr的代码需要C代码)。但是这证明了基本解决方案可以非常简单。


2
最好的方法是使用最长公共子串算法(不要与同名的最长公共子序列算法混淆),然后检查其长度。
use String::LCSS_XS qw( lcss );

my $longest = lcss("MatchPartOfThisString", "fThisDiff");
say length($longest);

如果你有非常长的字符串并且想要挤出每一毫秒,一个定制版本的算法可以在找到目标长度时立即停止,并避免构建字符串,这样会更快。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接