Perl's Glob ha un limite?


9

Sto eseguendo le seguenti stringhe di ritorno in attesa di 5 caratteri:

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

ma restituisce solo 4 caratteri:

anbc
anbd
anbe
anbf
anbg
...

Tuttavia, quando riduco il numero di caratteri nell'elenco:

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

restituisce correttamente:

aamid
aamie
aamif
aamig
aamih
...

Qualcuno può dirmi cosa mi manca qui, c'è un limite di qualche tipo? o c'è un modo per aggirare questo?

Se fa qualche differenza, restituisce lo stesso risultato in entrambi perl 5.26eperl 5.28


In precedenza: stackoverflow.com/a/58852104 stackoverflow.com/a/58853045 Utilizzare un modulo che fornisce un iteratore invece di abusare della funzione glob. p3rl.org/Algorithm::Combinatorics p3rl.org/Algorithm::Loops
daxim

Grazie @daxim. Il problema è che sto lottando per caricare moduli di qualsiasi tipo in questo momento, ho un problema con cpan che si lamenta di Win32 :: Console, eppure ppm non è disponibile in perl 5.28, quindi posso caricare il modulo per cpan per smettere di lamentarmi.
Gerry,

Grazie @zdim apprezzo tutto il tempo e lo sforzo.
Gerry,

Ho appena realizzato ... vuoi assolutamente mescolarlo (randomizzato) o solo l'elenco completo?
zdim,

@zdim solo un elenco completo. :)
Gerry,

Risposte:


6

Tutto ha qualche limitazione.

Ecco un modulo Perl puro che può farlo per te in modo iterativo. Non genera l'intero elenco in una sola volta e inizi a ottenere immediatamente i risultati:

use v5.10;

use Set::CrossProduct;

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

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

Amico, non capisci quanto sono felice adesso. Grazie mille!!
Gerry,

3
Algorithm :: Loops's NestedLoopsalso also also also: use Algorithm::Loops qw( NestedLoops ); NestedLoops([ ([ 'a'..'z' ]) x 5 ], sub { say join '', @_ } ); (Una risposta a una precedente domanda dell'OP menzionava che potevano usarlo se fossero rimasti senza memoria ...)
ikegami

8

Il globprimo crea tutte le possibili espansioni di nomi di file, quindi in primo luogo genererà l'elenco completo dal glob / pattern in stile shell che viene fornito. Solo allora itererà su di esso, se utilizzato in un contesto scalare. Ecco perché è così difficile (impossibile?) Sfuggire all'iteratore senza esaurirlo; vedi questo post .

Nel tuo primo esempio sono 26 5 stringhe ( 11_881_376), ciascuna lunga cinque caratteri. Quindi un elenco di ~ 12 milioni di stringhe, con un totale (ingenuo) superiore a 56 Mb ... più l'overhead per uno scalare, che credo sia almeno di 12 byte o simili. Quindi all'ordine di un 100 Mb, almeno, proprio lì in un elenco.

Non sono a conoscenza di limiti formali su lunghezze di cose in Perl (tranne che in regex), ma globtutto ciò internamente e ci devono essere limiti non documentati - forse alcuni buffer sono superati da qualche parte, internamente? È un po 'eccessivo.

Per ovviare a questo, genera quell'elenco di stringhe di 5 caratteri in modo iterativo, invece di lasciare globrotolare la sua magia dietro le quinte. Quindi non dovrebbe assolutamente avere problemi.

Tuttavia, trovo il tutto un po 'grande per il comfort, anche in quel caso. Consiglio vivamente di scrivere un algoritmo che generi e fornisca un elemento elenco alla volta (un "iteratore"), e di lavorare con quello.

Ci sono buone librerie che possono farlo (e molto altro), alcune delle quali sono Algorithm :: Loops consigliate in un precedente post su questo argomento (e in un commento), Algorithm :: Combinatorics (stesso commento), Set::CrossProductda un'altra risposta Qui ...

Si noti inoltre che, sebbene si tratti di un uso intelligente di glob, la libreria deve funzionare con i file. A parte l'uso improprio in linea di principio, penso che controllerà ciascuno dei (i ~ 12 milioni) nomi per una voce valida ! (Vedi questa pagina .) Questo è un sacco di lavoro sul disco non necessario. (E se dovessi usare "globs" come *o ?su alcuni sistemi, verrà restituito un elenco con solo stringhe che contengono file, quindi otterrai tranquillamente risultati diversi.)


 Ricevo 56 byte per una dimensione di uno scalare di 5 caratteri. Sebbene ciò sia per una variabile dichiarata, che può richiedere un po 'più di uno scalare anonimo, nel programma di test con stringhe di lunghezza 4 la dimensione totale effettiva è effettivamente un buon ordine di grandezza più grande di quello calcolato ingenuamente. Quindi la cosa reale potrebbe essere nell'ordine di 1Gb, in una sola operazione.

Aggiornamento   Un semplice programma di test che genera quell'elenco di stringhe lunghe 5 caratteri (usando lo stesso globapproccio) è stato eseguito per 15 minuti su un computer di classe server e ha richiesto 725 Mb di memoria.

Ha prodotto il giusto numero di stringhe lunghe effettive da 5 caratteri, apparentemente corrette, su questo server.


@Gerry In primo luogo, non sono sicuro che il problema abbia dei limiti; esaminandolo ... Forse generare prima l'elenco, in modo iterativo (non tutto in una volta), e memorizzarlo in un array adeguato? Che sicuramente non raggiungerà alcun limite, una "manciata" di stringhe da 5 caratteri. (È anche diagnostico --- se funziona, allora è davvero un limite interno.)
zdim

@Gerry Non hai bisogno di moduli --- costruisci prima la lista (di stringhe di cinque caratteri) in un array, pezzo per pezzo, invece di raggrupparlo insieme usando glob. (Ciò richiederà qualche algoritmo semplice, altro. Forse quello che ho pubblicato nella tua domanda precedente? È un buon debug - se riesci a ottenere quell'elenco senza problemi, sai che i limiti vengono spinti qui.) Ho aggiunto alcune stime di dimensione che sto arrivando al post ...
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"... e fammi controllare ... ora è stato eseguito in 30 secondi, ciò che lo conferma dato il funzionamento della cache qui. Ho anche controllato RSS con strumenti esterni mentre stava funzionando.
zdim,

@Gerry Stesso comportamento su v5.29.2 (~ 600Mb ora) ... ancora in esecuzione su quella cache su questo server :)))
zdim

@Gerry Risultato da un altro computer di classe server, con v5.16 - 28 minuti (sottovalutato mentre stava funzionando!) E 750Mb. Ora ripeti sotto 5.29.2 e di nuovo ~ 600Mb. Stringhe corrette e numero corretto di esse (esattamente 26**5)
zdim
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.