我想将一段perl代码转换为python,但我对perl及其语法并不熟悉。
特别是,我只是对perl中的map运算符和下面代码中的shift运算符感到困惑。
(@M) = ($y =~ m/((?:\d+:ITEM7 \d+:\d+ )+(?:\d+:ITEM7A \d+:\d+ )*)(?:\d+:ITEM8 \d+:\d+\s*)+/g);
$best = 0;
$bestseq = "";
for($i = 0; $i < scalar(@M); ++$i) {
$m = $M[$i];
$m =~ s/\d+://g;
(@m) = (split / /, $m);
$v = 0;
$z = length_in_words($M[$i]);
map { $v += $_ if($_ =~ m/^\d+$/); } @m;
if($v > $best) { $best = $v; $bestseq = $M[$i]; }
}
sub length_in_words {
my $x = shift;
my @k;
return scalar(@k = $x =~ m/(\S+)/sg);
}
我知道@M
基于python re.findall
分配一个数组,但我只是对地图函数和移位运算符以及它如何应用于@k
感到困惑
我该如何解决这个问题?
虽然你得到了ysth的完整解释,但我无法帮助它,只能改写它
一个简单的例子
use warnings;
use strict;
use List::Util qw(sum0);
my $y = ...
my @M = $y =~ /.../;
my ($best, $bestseq) = (0, '');
foreach my $m (@M) {
(my $new_m = $m) =~ s/\d+://g;
my @w = split ' ', $new_m; # CHANGED from original
my $v = sum0 grep { /^\d+$/ } @w;
if ($v > $best) {
$best = $v;
$bestseq = $new_m;
}
}
sub length_in_words {
return scalar split ' ', $_[0];
}
循环似乎执行以下操作。 @M
数组的每个元素都被\d+:
(连续数字后跟:
)修剪,然后分成单词。所有仅为数字的单词总结。这用于查找最大(“最佳”)此类总和并记录其元素。
一些评论
foreach
在处理中对数组元素进行别名,因此如果操作更改当前处理的元素,则数组也会更改。
原始代码不会改变@M
的元素,所以我首先将$m
复制到$new_m
并使用它。如果这无关紧要,@M
可能会在这个循环中改变,只需做$m =~ s/\d+://g;
,并在其他地方使用$m
而不是$new_m
。$i
,因此直接迭代数组元素$z
未使用,已删除map
总结了@m
元素的过滤(仅数字)子集sum0
,它给出空列表输入零split / /, $m
用一个空格分割标量$m
。我强烈怀疑的意图是将$m
解析成单词,因此被所有连续的空格分开。因此我用
my @w = split ' ', $new_m;
其中' '
是一种特殊模式,可以按任意数量的空格分割,并且还会丢弃前导和尾随空格。见split。我将它重命名为@w
,因为它显然是单词。还有一条评论:我会使用@words
,$val
(或其他),而不是单字母名称。
评论length_in_words()
中使用的代码和效率。
当然,有多种方法可以计算字符串中的单词数。下面的基准测试表明这里选择的最快
use warnings;
use strict;
use feature 'say';
use Benchmark 'cmpthese';
my $run_for = shift // 3; # seconds for each
my $text = " ah\n no \t hi end ";
sub split_scalar {
return scalar split ' ', $_[0];
}
sub regex_context {
my $wc =()= $_[0] =~ /\S+/g;
}
sub regex_while {
my $wc;
++$wc while $_[0] =~ /\S+/g;
return $wc;
}
cmpthese (-$run_for, {
split_scalar => sub { split_scalar($text) },
regex_context => sub { regex_context($text) },
regex_while => sub { regex_while($text) },
});
在一个体面的桌面上的v5.24.4下打印
Rate regex_context regex_while split_scalar regex_context 1119833/s -- -7% -90% regex_while 1203020/s 7% -- -89% split_scalar 11351365/s 914% 844% --
首先,在标量上下文中使用split
这样一个巨大的优势对我来说是令人惊讶的,我猜它是由于split
中的特定优化,这个用例从中受益。
更有趣的是,当用10_000个单词分割一个字符串时,标量分割方式甚至更加优越 - 它达到了4026%。
在我的测试中,这显示了在桌面和服务器上重复运行的一致结果,v5.16.3和v5.24.4,在旧的Perl下有以下细微差别。
使用v5.16,split
的优势稍微小一些(尽管仍然是7的因素),并且在正则表达式中使用=()=
的上下文并没有比分配给数组并返回它的scalar
更好(在v5.24中)它是30-40%,所以我省略了生成数组变量的情况。
但请注意,在v5.12之前,标量背景中的split
具有surprising (nasty) behavior。鉴于问题中的代码,有可能在旧的Perl上运行(运行?)(不能解释所显示的代码),在这种情况下,请使用基于正则表达式的替代方法而不是split
。
感谢melpomene的评论。
map通常用于将一个列表转换为另一个列表;在这里它被滥用简单地循环@m
。
代码相当于:
for my $maybe_number (@m) {
if ($maybe_number =~ /^\d+$/) {
$v += $maybe_number;
}
}
总结@m
的所有元素,只是一个或多个数字。
一个子中的my $x = shift;
将子的第一个参数分配给$x
。
单词中的最后一行长度查找非空白字符的所有序列,并将它们分配给@k
。该赋值放置在标量上下文中,该上下文返回分配的元素数。因此它计算了sub的参数中有多少“单词”(非空白字符序列)。