Perl's Glob'un bir sınırlaması var mı?


9

Ben 5 karakter aşağıdaki aşağıdaki dönüş dizeleri bekliyor:

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";
}

ancak yalnızca 4 karakter döndürür:

anbc
anbd
anbe
anbf
anbg
...

Ancak, listedeki karakter sayısını azalttığımda:

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

doğru bir şekilde geri döner:

aamid
aamie
aamif
aamig
aamih
...

Birisi bana burada neyi kaçırdığımı söyleyebilir mi, bir tür sınır var mı? Yoksa bunun bir yolu var mı?

O fark edecekse, her iki aynı sonucu verir perl 5.26veperl 5.28


Önceden: stackoverflow.com/a/58852104 stackoverflow.com/a/58853045 glob işlevini kötüye kullanmak yerine yineleyici sağlayan bir modül kullanın. p3rl.org/Algorithm::Combinatorics p3rl.org/Algorithm::Loops
daxim

Teşekkürler @daxim. Sorun şu anda herhangi bir tür modülleri yüklemek için mücadele ediyorum, ben Win32 :: Konsol hakkında şikayet bir cpan sorunu var, ama ppm perl 5.28 de mevcut değil bu yüzden şikayet durdurmak için cpan için yükleyebilirsiniz.
Gerry

Teşekkürler @zdim her zaman ve çaba için teşekkür ederiz.
Gerry

Az önce farkettim ... bu karışık (rastgele) veya sadece tam liste ister misiniz?
zdim

@zdim sadece tam bir liste. :)
Gerry

Yanıtlar:


6

Her şeyin bir sınırlaması var.

İşte size tekrar tekrar yapabilen saf bir Perl modülü. Listenin tamamını aynı anda oluşturmaz ve hemen sonuç almaya başlarsınız:

use v5.10;

use Set::CrossProduct;

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

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

Dostum, şu an ne kadar mutlu olduğumu anlamıyorsun. Çok teşekkür ederim!!
Gerry

3
Algoritma :: Döngüler NestedLoopsde kullanılabilir: use Algorithm::Loops qw( NestedLoops ); NestedLoops([ ([ 'a'..'z' ]) x 5 ], sub { say join '', @_ } ); (OP tarafından daha önceki bir soruya verilen bir cevap, hafızası tükeniyorsa bunu kullanabileceklerini belirtti ...)
ikegami

8

Birincisi globtüm olası dosya adı genişletmelerini oluşturur, böylece ilk önce verilen kabuk stili glob / deseninden tam listeyi oluşturur . Ancak bundan sonra skaler bağlamda kullanılırsa tekrarlanır. Bu yüzden yineleyiciyi yormadan kaçmak çok zor (imkansız?); bu gönderiye bakın .

İlk örneğinizde , her biri 5 karakter uzunluğunda 26 5 dize ( 11_881_376). Yani ~ 12 milyon dizelerin bir listesi, (saf) toplam 56Mb'den fazla ... artı en azından 12 bayt veya benzeri olduğunu düşünüyorum bir skaler için ek yük. Yani 100Mb'lerin sırasına göre, en azından, orada bir listede.

Perl'deki (regex dışında) şeylerin uzunlukları hakkında herhangi bir resmi sınırın farkında değilim ama globtüm bunlar dahili olarak ve belgelenmemiş sınırlar olmalı - belki bazı tamponlar bir yerde, dahili olarak taşar mı? Biraz fazla.

Bunun bir yoluna gelince - globbüyüsünü sahnelerin arkasına yuvarlamak yerine 5 karakterlik dizelerin listesini tekrarlı bir şekilde oluşturun . O zaman kesinlikle bir problemi olmamalıdır.

Ancak, bu durumda bile her şeyi rahatlık için biraz büyük buluyorum. Gerçekten bir liste öğesi (bir "yineleyici") üreten ve sağlayan bir algoritma yazmanızı ve bununla çalışmanızı tavsiye ederim.

Bunu yapabilen (ve çok daha fazlası) iyi kütüphaneler var, bazıları Algoritma :: Bu konuda önceki bir gönderide (ve bir yorumda) önerilen döngüler , Algorithm :: Combinatorics (aynı yorum), Set::CrossProductbaşka bir cevaptan buraya ...

Ayrıca, bu akıllıca bir kullanım olsa da glob, kütüphane dosyalarla çalışmak içindir. Prensip olarak kötüye kullanmanın dışında, her bir (~ 12 milyon) ismin geçerli bir giriş olup olmadığını kontrol edeceğini düşünüyorum ! ( Bu sayfaya bakın .) Bu, gereksiz birçok disk işi. (Ve gibi "globs" kullanmak olsaydı *veya ?bazı sistemlerde bu size sessizce farklı sonuçlar olsun diye, aslında, dosyaları tek dizeler bir listesini döndürür.)


 5 karakterlik bir skaler boyut için 56 bayt alıyorum. Anonim bir skalerden biraz daha fazlasını alabilen beyan edilmiş bir değişken için olsa da, uzunluk-4 dizeli test programında gerçek toplam boyut, saf olarak hesaplanandan daha büyük bir büyüklük sırasıdır. Yani gerçek şey, bir operasyonda 1Gb civarında olabilir.

Güncelleme   5 karakterlik uzun dizelerin (aynı globyaklaşımı kullanarak ) listesini üreten basit bir test programı, sunucu sınıfı bir makinede 15 ish dakika sürdü ve 725 Mb bellek aldı.

Bu sunucuda doğru görünen gerçek 5 karakter uzunluğunda dizeler üretiyordu.


@Gerry İlk olarak, sorunun sınırlarla olduğundan emin değilim; içine bakarak ... Belki de listeyi ilk önce, yinelemeli olarak üretin (hepsini bir kerede değil) ve uygun bir dizide saklayın? Bu kesinlikle herhangi bir sınırın yakınında hiçbir yere, 5 karakterlik dizelerin "bir avuç" ulaşamaz. (Aynı zamanda tanı --- bu işe yararsa gerçekten bir iç sınır.)
zdim

@Gerry Modüllere gerek yok --- sadece listeyi (beş karakterlik dizelerden) kullanarak bir araya toplamak yerine, önce bir dizi halinde parça halinde oluşturun glob. (Bu bazı basit fikirli, başka bir algoritmaya ihtiyaç duyacaktır. Belki de önceki sorunuza gönderdiğim şey?
gönderiyorum

@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"... ve kontrol edeyim ... şimdi 30 saniye içinde koştu, burada önbelleklemenin nasıl çalıştığı onaylandı. Ayrıca RSS'yi harici araçlarla kontrol ederken de kontrol ettim.
zdim

@Gerry v5.29.2'de aynı davranış (~ 600Mb şimdi) ... hala bu sunucuda bu önbelleğe biniyor :)))
zdim

@Gerry v5.16 - 28 dakika (devam ederken küçümseniyor!) Ve 750Mb ile başka bir sunucu sınıfı makineden sonuç. Şimdi 5.29.2 ve tekrar ~ 600Mb altında reran. Doğru dizeler ve bunların doğru sayısı (tam olarak 26**5)
zdim
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.