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


以前:stackoverflow.com/a/58852104 stackoverflow.com/a/58853045 glob関数を悪用する代わりに、イテレータを提供するモジュールを使用しました。p3rl.org/Algorithm::Combinatorics p3rl.org/Algorithm::Loops
daxim

@daximに感謝します。問題は、現在、あらゆる種類のモジュールをロードするのに苦労していることです。Win32:: Consoleについてcpanの問題がありますが、Perl 5.28でもppmを使用できないため、cpanのモジュールをロードして、問題を解消できます。
ジェリー

@zdimに感謝します。
ジェリー

私は気づきました...これをシャッフル(ランダム化)しますか、それとも完全なリストにしますか?
zdim

@zdimは完全なリストです。:)
ジェリー

回答:


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

glob1 つ目は、可能なすべてのファイル名拡張を作成するため、指定されたシェルスタイルのglob / patternから完全なリストを最初に生成します。スカラーコンテキストで使用されている場合にのみ、その後反復します。これが、反復子を使い果たすことなくエスケープすることが非常に難しい(不可能か?)理由です。この投稿を参照してください。

最初の例では、26 個の5文字列(11_881_376)で、それぞれ5文字です。したがって、約1200万個の文字列のリストで、(単純な)合計が56Mbを超えており、それに加えて、スカラーのオーバーヘッドが最低でも12バイト程度あると思います。したがって、少なくとも1つのリストに100Mbのオーダーがあります。

私はPerl(正規表現以外)での長さに関する正式な制限を認識していませんが、globすべて内部で行っており、文書化されていない制限があるはずです-おそらく一部のバッファーが内部でオーバーランしていますか?それは少し過剰です。

これを回避する方法については、5文字の文字列のリストを繰り返し生成するのではなくglob、舞台裏で魔法をかけるのではありません。そうすれば、絶対に問題はないはずです。

ただし、その場合でも、快適さのために全体が少し大きいと思います。一度に1つのリスト要素を生成して提供するアルゴリズム(「イテレーター」)を作成し、それを使用することをお勧めします。

それを行うことができる優れたライブラリがあります(そしてもっとたくさん)、そのうちのいくつかはこの問題についての以前の投稿で推奨されているAlgorithm :: Loopsです(そしてコメントで)、Algorithm :: Combinatorics(同じコメント)、Set::CrossProduct別の答えからここに ...

また、これはの賢い使い方ですglobが、ライブラリはファイルを操作するためのものです。原則としてそれを誤用することは別として、私はそれが有効なエントリのためにそれぞれ(〜1200万)の名前をチェックすると思います!(このページを参照してください。)これは、多くの不要なディスク作業です。(そして、「グロブ」を使用する場合、*または?一部のシステムでは、実際にファイルがある文字列のみのリストを返すため、静かに異なる結果が得られます。)


 5文字のスカラーのサイズで56バイトを取得しています。これは宣言された変数用であり、匿名スカラーより少しかかる場合がありますが、長さ4の文字列を使用したテストプログラムでは、実際の合計サイズは単純に計算されたものよりも桁違いに大きくなっています。したがって、1回の操作で本物が1Gbのオーダーになる可能性があります。

更新   5文字の長い文字列のリストを生成する簡単なテストプログラム(同じglobアプローチを使用)は、サーバークラスのマシンで15分間実行され、725 MBのメモリを消費しました。

このサーバーでは、正しいように見える、正しい数の実際の5文字の長い文字列が生成されました。


@Gerryまず、問題が制限にあるかどうかはわかりません。それを調べています...おそらく、リストを(一度にすべてではなく)最初に繰り返し生成し、適切な配列に格納しますか?それは確かに制限に近づくことはありません。5文字の文字列の "一握り"です。(これも診断です---それが機能する場合、それは確かにいくつかの内部制限です。)
zdim

@Gerryモジュールは必要ありません---(5文字の文字列の)リストを最初に配列に構築し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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.