Glob ของ Perl มีข้อ จำกัด หรือไม่?


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 ปัญหาคือฉันพยายามโหลดโมดูลทุกประเภทตอนนี้ฉันมีปัญหา cpan ที่บ่นเกี่ยวกับ Win32 :: Console แต่ ppm ไม่พร้อมใช้งานใน perl 5.28 ดังนั้นฉันจึงสามารถโหลดโมดูลสำหรับ cpan เพื่อหยุดการบ่น
Gerry

ขอบคุณ @zdim ขอบคุณตลอดเวลาและความพยายาม
เจอร์รี่

ฉันเพิ่งรู้ว่า ... คุณต้องการสับนี้ (สุ่ม) ทั้งหมดหรือเพียงแค่รายการที่สมบูรณ์หรือไม่
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
    }

ผู้ชายคุณไม่เข้าใจว่าตอนนี้ฉันมีความสุขแค่ไหน ขอบคุณมาก!!
เจอร์รี่

3
อัลกอริทึม :: ลูปNestedLoopsสามารถใช้งานได้: use Algorithm::Loops qw( NestedLoops ); NestedLoops([ ([ 'a'..'z' ]) x 5 ], sub { say join '', @_ } ); (คำตอบสำหรับคำถามก่อนหน้านี้โดย OP กล่าวถึงพวกเขาสามารถใช้สิ่งนี้ได้หากหน่วยความจำไม่
เพียงพอ

8

globแรกสร้างขยายชื่อไฟล์ที่เป็นไปได้ทั้งหมดดังนั้นมันเป็นครั้งแรกที่จะสร้างรายการสินค้าจากเปลือกสไตล์ glob / รูปแบบก็จะได้รับ จากนั้นจะวนซ้ำถ้าใช้ในบริบทสเกลาร์ นั่นเป็นสาเหตุที่ยาก (เป็นไปไม่ได้) ที่จะหลบหนีตัววนซ้ำโดยไม่ต้องเหนื่อย ดูโพสต์นี้

ในตัวอย่างแรกของคุณนั่นคือ 26 5สาย ( 11_881_376) แต่ละตัวมีความยาวห้าตัว ดังนั้นรายการของสตริง ~ 12 ล้านมีทั้งหมด (ไร้เดียงสา) เกิน 56Mb ... บวกค่าโสหุ้ยสำหรับเซนต์คิตส์และเนวิสซึ่งฉันคิดว่าอย่างน้อย 12 ไบต์หรือเช่นนั้น ดังนั้นตามคำสั่งของ 100Mb อย่างน้อยที่สุดมีอยู่ในรายการเดียว

ฉันไม่ได้ตระหนักถึงข้อ จำกัด อย่างเป็นทางการใด ๆ เกี่ยวกับความยาวของสิ่งต่าง ๆ ใน Perl (นอกเหนือจาก regex) แต่globทำทุกอย่างภายในและต้องมีข้อ จำกัด ที่ไม่มีเอกสาร - บางทีบัฟเฟอร์บางตัวถูกบุกรุกที่ไหนสักแห่งภายใน? มันมากไปหน่อย

สำหรับวิธีการนี้ - สร้างรายการของสตริง 5 char ซ้ำ ๆ แทนที่จะปล่อยให้globมันหมุนไปด้านหลังฉาก ถ้าอย่างนั้นก็ไม่ควรมีปัญหา

อย่างไรก็ตามฉันพบว่าสิ่งทั้งหมดนั้นค่อนข้างใหญ่เพื่อความสบายแม้ในกรณีนั้น ฉันอยากจะแนะนำให้เขียนอัลกอริทึมที่สร้างและนำเสนอองค์ประกอบรายการทีละรายการ ("ตัววนซ้ำ") และทำงานกับสิ่งนั้น

มีห้องสมุดที่ดีที่สามารถทำเช่นนั้นได้ (และอีกมาก) ซึ่งบางส่วนเป็นAlgorithm :: Loops ที่แนะนำในโพสต์ก่อนหน้าในเรื่องนี้ (และในความคิดเห็น), Algorithm :: Combinatorics (ความคิดเห็นเดียวกัน) Set::CrossProductจากคำตอบอื่น ที่นี่ ...

นอกจากนี้โปรดทราบว่าแม้ว่านี่จะเป็นการใช้งานที่ชาญฉลาดglobแต่ไลบรารี่ก็มีไว้เพื่อทำงานกับไฟล์ต่างๆ นอกจากหลักการใช้ผิดฉันคิดว่ามันจะตรวจสอบชื่อ (~ 12 ล้าน) แต่ละชื่อสำหรับรายการที่ถูกต้อง ! (ดูหน้านี้) นั่นเป็นดิสก์ที่ไม่จำเป็นจำนวนมาก (และถ้าคุณต้องใช้ "globs" เช่น*หรือ?ในบางระบบจะส่งคืนรายการที่มีสตริงที่มีไฟล์จริงเท่านั้นดังนั้นคุณจะได้ผลลัพธ์ที่ต่างกันอย่างเงียบ ๆ )


 ฉันได้รับ 56 ไบต์สำหรับขนาดสเกลาร์ 5 ตัว ในขณะที่ใช้สำหรับตัวแปรที่ประกาศซึ่งอาจใช้เวลานานกว่าสเกลาร์นิรนามเล็กน้อยในโปรแกรมทดสอบที่มีความยาว -4 สตริงขนาดโดยรวมที่แท้จริงย่อมเป็นลำดับที่มีขนาดใหญ่กว่าขนาดที่คำนวณอย่างไร้เดียงสา ดังนั้นของจริงอาจอยู่ที่อันดับ 1Gb ในการดำเนินการครั้งเดียว

อัปเดต   โปรแกรมทดสอบอย่างง่ายที่สร้างรายการของสตริงความยาว 5 อักขระ (ใช้globวิธีการเดียวกัน) ใช้เวลา 15-ish นาทีบนเครื่องที่ใช้คลาสเซิร์ฟเวอร์และใช้หน่วยความจำ 725 Mb

มันสร้างจำนวนที่ถูกต้องของสตริงความยาว 5 char ที่แท้จริงดูเหมือนถูกต้องบนเซิร์ฟเวอร์นี้


@Gerry ก่อนอื่นฉันไม่แน่ใจว่าปัญหาเกิดขึ้นกับขีด จำกัด ; มองเข้าไปในมัน ... อาจสร้างรายการแรกซ้ำ ๆ (ไม่ใช่ทั้งหมดในคราวเดียว) และเก็บไว้ในอาร์เรย์ที่เหมาะสมใช่ไหม แน่นอนว่าจะไม่เข้าไปใกล้ขีด จำกัด ใด ๆ สตริง 5 กำมือ (นอกจากนี้ยังเป็นการวินิจฉัย --- หากใช้งานได้จริง ๆ แล้วก็เป็นข้อ จำกัด ภายในบางอย่าง)
274

@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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.