Perl的Glob有限制吗?


9

我正在运行以下期望返回5个字符的字符串:

while (glob '{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z}'x5) {
  print "$_\n";
}

但它仅返回4个字符:

anbc
anbd
anbe
anbf
anbg
...

但是,当我减少列表中的字符数时:

while (glob '{a,b,c,d,e,f,g,h,i,j,k,l,m}'x5) {
  print "$_\n";
}

它正确返回:

aamid
aamie
aamif
aamig
aamih
...

有人可以告诉我我在这里缺少什么吗,是否有某种限制?还是有办法解决?

如果有什么不同,则在perl 5.26和中都返回相同的结果perl 5.28



谢谢@daxim。问题是我现在正在努力加载任何类型的模块,我在抱怨Win32 :: Console遇到了cpan问题,但是ppm在perl 5.28中也不可用,因此我可以为cpan加载模块以停止抱怨。
格里

感谢@zdim感谢您一直以来的努力。
格里

我只是意识到……您是要完全改组(随机化)还是只是完整列表?
zdim

@zdim只是完整列表。:)
格里(Gerry)

Answers:


6

一切都有一定的局限性。

这是一个纯Perl模块,可以为您反复进行。它不会立即生成整个列表,您会立即开始获得结果:

use v5.10;

use Set::CrossProduct;

my $set = Set::CrossProduct->new( [ ([ 'a'..'z' ]) x 5 ] );

while( my $item = $set->get ) {
    say join '', @$item
    }

男人,你不明白我现在有多高兴。非常感谢你!!
格里

3
Algorithm :: Loops NestedLoops也可以使用: use Algorithm::Loops qw( NestedLoops ); NestedLoops([ ([ 'a'..'z' ]) x 5 ], sub { say join '', @_ } ); (OP先前回答的一个问题提到,如果内存不足,他们可以使用此方法...)
ikegami

8

glob一个创建所有可能的文件扩展名,因此它将首先从给定的shell样式的glob / pattern 生成完整列表。如果在标量上下文中使用,则只有这样才能对其进行迭代。这就是为什么要逃避迭代器而不用尽它是如此困难(不可能?)的原因。看到这篇文章

在您的第一个示例中,有26个5个字符串(11_881_376),每个字符串5个字符。因此,大约有1200万个字符串的列表,(原始)总数超过56Mb ...加上标量的开销,我认为标量的开销至少为12个字节左右。因此,至少一个列表中至少有一个100Mb的数量级。

我不知道对Perl中的事物长度有任何正式的限制(正则表达式中除外),但是glob内部是否全部都存在,并且必须有未记录的限制-也许某些缓冲区在内部某个地方溢出了?有点过分了。

关于此问题的解决方法-迭代生成5个字符的字符串列表,而不是让其glob幕后推手。那么它绝对不应该有问题。

但是,即使在那种情况下,我发现整个过程还是有点舒适。我真的建议编写一种算法,一次生成并提供一个列表元素(“迭代器”),然后使用该算法。

有很多好的库可以做到这一点(还有更多),其中一些是以前的帖子(和评论)中推荐的Algorithm :: LoopsAlgorithm :: Combinatorics(同样的评论),Set::CrossProduct来自另一个答案。这里 ...

还要注意,虽然这是的巧妙用法glob,但该库是用于处理文件的。除了原则上滥用它外,我认为它将检查(〜1200万个)名称中的每个名称是否有效!(请参阅本页。)这是很多不必要的磁盘工作。(并且,如果您要像在某些系统上那样使用“ globs” *?在某些系统上使用它,它会返回仅包含实际上具有文件的字符串的列表,因此您会悄悄地获得不同的结果。)


 我得到56个字节的5个字符的标量。尽管这是一个声明的变量,它可能比匿名标量花费更多,但是在具有长度为4的字符串的测试程序中,实际总大小确实比幼稚计算的大小大一个数量级。因此,一次操作中,真实的东西很可能约为1Gb。

更新   一个简单的测试程序(使用相同的glob方法)生成5字符长字符串的列表,在服务器级计算机上运行了15分钟,并占用了725 Mb的内存。

它确实在此服务器上产生了正确数目的实际5字符长字符串,看似正确。


@Gerry首先,我不确定问题是否存在局限性;寻找它...也许首先迭代生成列表(不是一次全部生成),然后将其存储在适当的数组中?这肯定不会达到任何限制,即“少数” 5个字符的字符串。(这也是诊断性的---如果
可行,

@Gerry不需要模块---只需先将(五个字​​符的字符串)列表逐步地构建到数组中,而不是使用来将其组合在一起glob。(这将需要一些头脑简单的其他算法。也许是我在上一个问题中发布的内容?这是很好的调试-如果您可以得到没有问题的列表,那么您知道这里已经施加了限制。)我添加了一些大小估计我要去担任职位...
zdim

@Gerry time perl -MDevel::Size=total_size -wE'$chs = join ",", "a".."z"; @items = glob "{$chs}"x5; say STDERR "Total memory: ", total_size(\@items)/(1024**2), " Mb"...让我检查一下...现在它运行了30秒,考虑到这里的缓存工作原理,它可以证实这一点。进行过程中,我还使用外部工具检查了RSS。
zdim

@Gerry在v5.29.2上的行为相同(现在约600Mb)...仍在此服务器上的该缓存中运行:)))
zdim

@Gerry来自另一台服务器类计算机的结果,具有v5.16-28分钟(运行过程中低估了它的时间!)和750Mb。现在重新达到5.29.2,并再次达到〜600Mb。正确的字符串和正确的数目(准确地26**5
zdim
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.