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에 대한 모듈을로드하여 불평을 중지 할 수 있습니다.
— Gerry

감사합니다 @zdim은 모든 시간과 노력에 감사드립니다.
— Gerry

방금 깨달았습니다 ...이 셔플 (무작위 화)을 원하십니까, 아니면 전체 목록을 원하십니까?
— zdim

@zdim은 전체 목록입니다. :)
— Gerry

답변:


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
    }

당신은 내가 지금 얼마나 행복한 지 이해하지 못합니다. 대단히 감사합니다 !!
— Gerry

3
알고리즘 :: 루프의이 NestedLoops또한 사용될 수있다 : use Algorithm::Loops qw( NestedLoops ); NestedLoops([ ([ 'a'..'z' ]) x 5 ], sub { say join '', @_ } ); (방공호에 의해 이전 질문에 대한 답변들이 메모리 부족한다면 그들은이를 사용할 수 있습니다 언급 ...)
— 이케 가미

8

첫 glob번째는 가능한 모든 파일 이름 확장명을 작성하므로, 주어진 쉘 스타일 glob / pattern에서 전체 목록 을 먼저 생성합니다 . 스칼라 컨텍스트에서 사용되는 경우에만 반복됩니다. 그것이 반복자를 소진하지 않고 탈출하는 것이 너무 어려운 이유입니다. 이 게시물을 참조하십시오 .

첫 번째 예에서는 26 5 개의 문자열 ( 11_881_376)이며 각각 5 자입니다. 따라서 ~ 1,200 만 개의 문자열 목록과 총 순이익이 56Mb를 초과합니다 ... 스칼라의 오버 헤드와 최소 12 바이트 정도라고 생각합니다. 따라서 100Mb의 순서로 최소한 하나의 목록에 있습니다. †

나는 Perl (정규식이 아닌)의 길이에 대한 공식적인 제한을 알고 glob있지 않지만 내부적으로 그리고 문서화되지 않은 한계가 있어야합니다. 어쩌면 일부 버퍼가 내부 어딘가에서 오버런됩니까? 조금 과도합니다.

이 문제를 해결하는 방법 glob은 마술을 장면 뒤에서 굴리는 대신 5 문자 문자열 목록을 반복적으로 생성하는 것입니다 . 그렇다면 절대 문제가 없어야합니다.

그러나 그 경우에도 모든 것이 편안함을 위해 조금 큽니다. 한 번에 하나의 목록 요소 ( "반복자")를 생성하고 제공하는 알고리즘을 작성하고 작업하는 것이 좋습니다.

그것을 할 수있는 좋은 라이브러리가 있으며 그중 일부는 Algorithm :: Loops : 이 문제에 대한 이전 게시물 (및 주석), Algorithm :: Combinatorics (동일한 주석), Set::CrossProduct다른 대답에서 권장됩니다 여기 ...

또한 이것이 현명하게 사용되는 반면 glob라이브러리는 파일로 작업하기위한 것입니다. 원칙적으로 그것을 잘못 사용하는 것 외에도 유효한 항목에 대해 (~ 1,200 만) 이름을 검사 할 것이라고 생각합니다 ! ( 이 페이지를 참조 하십시오 .) 불필요한 디스크 작업이 많이 있습니다. (그리고 당신이 좋아 "globs의"를 사용한다면 *또는 ?일부 시스템에서 당신이 조용히 다른 결과를 얻을 것, 그래서 실제로 파일이있는 경우에만 문자열 목록을 반환합니다.)


†  5 문자 스칼라 크기로 56 바이트를 얻습니다. 익명의 스칼라보다 조금 더 많은 변수가 필요하지만, 길이가 4 인 문자열이있는 테스트 프로그램에서 실제 총 크기는 순진하게 계산 된 것보다 큰 크기입니다. 따라서 실제 작업은 한 번의 작업으로 1Gb 정도일 수 있습니다.

업데이트   동일한 glob접근 방식을 사용하여 5 자 길이의 문자열 목록을 생성하는 간단한 테스트 프로그램은 서버급 컴퓨터에서 15 분 동안 실행되었으며 725MB의 메모리를 사용했습니다.

이 서버에서 올바른 수의 실제 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가 진행되는 동안 외부 도구로 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.