我正在尝试使用Perl或MATLAB从单行文本中解析几个数字。我的文字是:
t10_t20_t30_t40 _
现在在matlab中,我使用了以下脚本
str = 't10_t20_t30_t40_';
a = regexp(str,'t(\d+)_t(\d+)','match')
然后返回
a =
't10_t20' 't30_t40'
我想要的是它也返回't20_t30',因为这显然是匹配。为什么regexp没有扫描呢?
我转向Perl,并在Perl中写了以下内容:
#!/usr/bin/perl -w
$str = "t10_t20_t30_t40_";
while($str =~ /(t\d+_t\d+)/g)
{
print "$1\n";
}
,结果与matlab相同
t10_t20
t30_t40
但我真的希望“t20_t30”也在结果中。
谁能告诉我如何实现这一目标?谢谢!
[用解决方案更新]: 在同事的帮助下,我使用Perl提供的所谓“环视断言”确定了一个解决方案。
#!/usr/bin/perl -w
$str = "t10_t20_t30_t40_";
while($str =~ m/(?=(t\d+_t\d+))/g)
{print "$1\n";}
关键是在Perl中使用“零宽度前瞻断言”。当Perl(和其他类似的软件包)使用regexp扫描字符串时,它不会重新扫描上一次匹配中已扫描的内容。所以在上面的例子中,t20_t30永远不会出现在结果中。为了捕获它,我们需要使用零宽度超前搜索来扫描字符串,产生不排除后续搜索中的任何子串的匹配(参见上面的工作代码)。如果将“全局”修饰符附加到搜索(即m // g),搜索将从第零个位置开始并尽可能多地增加一次,使其成为“贪婪”搜索。
this blog post中详细解释了这一点。
表达式(?= t \ d + _t \ d +)匹配任何0宽度的字符串,后跟t \ d + _t \ d +,这将创建实际的“滑动窗口”。这有效地返回$ str中的所有t \ d + _t \ d +模式而没有任何排除,因为$ str中的每个位置都是0宽度的字符串。附加括号在进行滑动匹配(?=(t \ d + _t \ d +))时捕获模式,从而返回所需的滑动窗口结果。
答案 0 :(得分:2)
使用Perl:
#!/usr/bin/perl
use Data::Dumper;
use Modern::Perl;
my $re = qr/(?=(t\d+_t\d+))/;
my @l = 't10_t20_t30_t40' =~ /$re/g;
say Dumper(\@l);
<强>输出:强>
$VAR1 = [
't10_t20',
't20_t30',
't30_t40'
];
答案 1 :(得分:0)
regexp
算法找到匹配后,匹配的字符不会被考虑用于进一步的匹配(通常,这是他们想要的,例如.*
不是应该匹配这篇文章的每个可以想象的连续子串)。解决方法是在第一次匹配后再次开始搜索一个字符,并收集结果:
str = 't10_t20_t30_t40_';
sub_str = str;
reg_ex = 't(\d+)_t(\d+)';
start_idx = 0;
all_start_indeces = [];
all_end_indeces = [];
off_set = 0;
%// While there are matches later in the string and the first match of the
%// remaining string is not the last character
while ~isempty(start_idx) && (start_idx < numel(str))
%// Calculate offset to original string
off_set = off_set + start_idx;
%// extract string starting at first character after first match
sub_str = sub_str((start_idx + 1):end);
%// find further matches
[start_idx, end_idx] = regexp(sub_str, reg_ex, 'once');
%// save match if any
if ~isempty(start_idx)
all_start_indeces = [all_start_indeces, start_idx + off_set];
all_end_indeces = [all_end_indeces, end_idx + off_set];
end
end
display(all_start_indeces)
display(all_end_indeces)
matched_strings = arrayfun(@(st, en) str(st:en), all_start_indeces, all_end_indeces, 'uniformoutput', 0)