การผสมตัวอักษรและตัวเลขที่เป็นไปได้ทั้งหมด


13

ดังนั้นฉันต้องการสร้างชุดค่าผสมที่เป็นไปได้ทั้งหมดของอักขระตัวพิมพ์เล็กและตัวพิมพ์ใหญ่และตัวเลขที่สามารถสร้างสตริงอักขระได้ 5 ตัว

ความเป็นไปได้: a..z, A..Z และ 0..9

มีวิธีที่สง่างามของการทำเช่นนี้ในการทุบตีเลยหรือไม่?


1
คุณต้องการ จำกัด ตัวเองเป็น ASCII หรือสคริปต์ละตินหรือไม่? สิ่งที่เกี่ยวกับการกำกับเสียงเช่นการเน้นเสียง (é, â ... )?
Stéphane Chazelas

ขอบคุณสำหรับการติดตาม อัปเดตโพสต์ต้นฉบับสำหรับการชี้แจง
ardevd

จริงๆมันต้องที่จะอยู่ในทุบตี? ภาษาอย่าง Perl หรือ awk จะทำไหม?
terdon

1
ถ้าอย่างนั้นทำไมไม่เรียกแค่ Perl หรือ Python จาก bash? โดยเฉพาะอย่างยิ่งกับperlมันเป็นเรื่องง่ายมากที่จะใช้มันเป็นหนึ่งซับ
terdon

2
คุณกำลังพยายามที่จะเรียนรู้หรือต้องการผลลัพธ์หรือไม่? ในกรณีที่สองมีโปรแกรมมากมายที่ทำงานเช่น john the ripper ( john) และ like ซึ่งจะให้ความเป็นไปได้มากมาย
YoMismo

คำตอบ:


13

ต่อไปนี้เป็นโซลูชันทุบตีที่ใช้ความยาวที่ต้องการเป็นพารามิเตอร์ ( permute 5ในกรณีของคุณ):

#!/bin/bash
charset=({a..z} {A..Z} {0..9})
permute(){
  (($1 == 0)) && { echo "$2"; return; }
  for char in "${charset[@]}"
  do
    permute "$((${1} - 1 ))" "$2$char"
  done
}
permute "$1"

แม้ว่ามันจะเจ็บปวดช้า ฉันขอแนะนำ C หรือไม่ https://youtu.be/H4YRPdRXKFs?t=18s

#include <stdio.h>

//global variables and magic numbers are the basis of good programming
const char* charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
char buffer[50];

void permute(int level) {
  const char* charset_ptr = charset;
  if(level == -1){
    puts(buffer);
  }else {
   while(buffer[level]=*charset_ptr++) {
    permute(level - 1);
   }
  }
}

int main(int argc, char **argv)
{

  int length;
  sscanf(argv[1], "%d", &length); 

  //Must provide length (integer < sizeof(buffer)==50) as first arg;
  //It will crash and burn otherwise  

  buffer[length]='\0';
  permute(length - 1);
  return 0;
}

เรียกใช้:

make CFLAGS=-O3 permute && time ./permute 5 >/dev/null #about 20s on my PC

ภาษาระดับสูงใช้ความรุนแรงในการดูด (ซึ่งเป็นสิ่งที่คุณกำลังทำอยู่)


@ Stéphane Chazelas ขอบคุณมากสำหรับการแก้ไข ฉันกำลังเขียนสิ่งสกปรกโดยไม่สนใจข้อความ "เหมาะสม" เนื่องจากไม่จำเป็นในกรณีนี้ แต่ฉันรู้สึกซาบซึ้งใจมากสำหรับทางลัด!
PSkocik

ฉันลองbashวิธีแก้ปัญหาของคุณ มันเป็นเรื่องดีมาก; ผมชอบมันมาก. มันทำงานได้ดีประมาณ 24 ชั่วโมงก่อนที่ฉันจะสังเกตเห็นว่าระบบของฉันถูกล็อคอย่างสมบูรณ์ พยายามสิ่งที่คล้ายกับ `หลาม; ด้วยผลลัพธ์ที่คล้ายกันแม้ว่าจะเร็วกว่ามาก
เสียง

8

ในbashคุณสามารถลอง:

printf "%s\n" {{a..z},{A..Z},{0..9}}{{a..z},{A..Z},{0..9}}{{a..z},{A..Z},{0..9}}{{a..z},{A..Z},{0..9}}{{a..z},{A..Z},{0..9}}

แต่นั่นจะใช้เวลาตลอดไปและใช้หน่วยความจำของคุณหมด ดีที่สุดคือการใช้เครื่องมืออื่นเช่นperl:

perl -le '@c = ("A".."Z","a".."z",0..9);
          for $a (@c){for $b(@c){for $c(@c){for $d(@c){for $e(@c){
            print "$a$b$c$d$e"}}}}}'

ระวังนั่นคือ 6 x 62 5ไบต์ดังนั้น 5,496,796,992

คุณสามารถทำแบบนั้นวนซ้ำได้bashแต่bashเป็นกระสุนที่ช้าที่สุดในทิศตะวันตกซึ่งต้องใช้เวลาหลายชั่วโมง:

export LC_ALL=C # seems to improve performance by about 10%
shopt -s xpg_echo # 2% gain (against my expectations)
set {a..z} {A..Z} {0..9}
for a do for b do for c do for d do for e do
  echo "$a$b$c$d$e"
done; done; done; done; done

(ในระบบของฉันผลลัพธ์นั้นอยู่ที่ 700 kiB / s ซึ่งต่างจาก 20MiB / s ที่perlเทียบเท่า)


ฉันยังรู้สึกว่ามันจะเพิ่มคำตอบถ้าคุณเพิ่มวิธีการส่งออกไปยังไฟล์; อาจเป็นเพราะมันถูกสร้างขึ้นดังนั้นจึงไม่ทำลาย RAM ของคุณหรือหลังจากนั้นทั้งหมดในหน่วยความจำแคช
Hellreaver

2
@Hellreaver พวกเขาทั้งหมดเขียนไปยังไฟล์ (ไปที่ stdout ไม่ว่าไฟล์ใดที่เปิดอยู่หากเรียกใช้ในเทอร์มินัลไฟล์อุปกรณ์เช่น/dev/pts/somethingและคุณสามารถเปลี่ยนได้โดยใช้โอเปอเรเตอร์การเปลี่ยนเส้นทางเชลล์) ไม่ใช่หน่วยความจำ เอาต์พุตทั้งหมดในหน่วยความจำก่อนที่จะส่งออก (ไปยังไฟล์ที่เปิดเมื่อ stdout)
Stéphane Chazelas

4

นี่เป็นวิธีที่จะทำได้โดยการทุบตีโดยไม่ต้องใช้หน่วยความจำ 5 GB:

for c1 in {A..Z} {a..z} {0..9}
do
    for c2 in {A..Z} {a..z} {0..9}
    do
        for c3 in {A..Z} {a..z} {0..9}
        do
            for c4 in {A..Z} {a..z} {0..9}
            do
                for c5 in {A..Z} {a..z} {0..9}
                do
                    printf "%s\n" "$c1$c2$c3$c4$c5"
                done
            done
        done
    done
done

2

เวอร์ชั่นทุบตีนี้ยังไม่เร็วเท่า Perl แต่เร็วกว่าถึงห้าเท่าซ้อนกันห้าครั้ง:

printf -vtwo "%s " {{a..z},{A..Z},{0..9}}{{a..z},{A..Z},{0..9}}
for three in {{a..z},{A..Z},{0..9}}{{a..z},{A..Z},{0..9}}{{a..z},{A..Z},{0..9}}; do
    printf "$three%s\n" $two;
done

1

คุณสามารถใช้crunch(ซึ่งมีให้อย่างน้อยในการกระจายของกาลี)

crunch 5 5 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890

1

ดี ... สง่างามใช่เลย (เป็นเพียงตัวอย่างรวดเร็ว):

eval echo $(printf "%s" '{{a..z},{A..Z},{0..9}}'{,,} )

นิพจน์แบบเต็มส่วนใหญ่มีแนวโน้มที่จะบล็อกคอมพิวเตอร์ของคุณ:

eval echo $(printf "%s" '{{a..z},{A..Z},{0..9}}'{,,,,} )

หนึ่งในตัวเลือกที่ไม่ปิดกั้นคือการใช้หลายลูป:

nl=$'\n'; tab=$'\t'
n=${1:-3}
eval set -- "$2"

eval "varnames=($(echo {a..z}))"

for i in "${varnames[@]:0:$n}"; do
    header+='for '"$i"' do '
    middle+='$'"$i"
    traile+="done; "
done

loop="${header}${nl}    printf %s \"$middle\";${nl}$traile"
#echo "$loop"
eval "$loop"

เรียกว่าชอบ:

./script 3 '{a..z} {A..Z} {0..9}'

โดยที่อาร์กิวเมนต์แรกคือจำนวนอักขระและตัวที่สองคือรายการ (คั่นด้วยช่องว่าง) ของอักขระที่ใช้

ที่จะสร้างตัวแปร ( loop) พร้อมกับสคริปต์เพื่อเรียกใช้และ eval ตัวสุดท้ายจะเรียกใช้งานสคริปต์นั้น ตัวอย่างเช่น:

$ ./script 5 '{a..z} {A..Z} {0..9}'

ค่าของloopจะเป็น:

for a do for b do for c do for d do for e do
    echo "$a$b$c$d$e";
done; done; done; done; done;

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