Apa ROT ini? - mendekripsi ROT-n


25

Berikut adalah huruf-huruf alfabet bahasa Inggris sesuai frekuensi:

e t a o i n s h r d l c u m w f g y p b v k j x q z

Artinya, eadalah surat yang paling sering digunakan, dan zmerupakan yang paling tidak umum. (Data dari Wikipedia .)

Tantangan Anda adalah mengambil beberapa teks ber-ROT, seperti:

ocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvaz

Ini adalah teks "thisisaverysecretmessagessatisethsveryureecafe dan safe" yang "dienkripsi" melalui ROT-21 (setengah dari 42). Program Anda, menggunakan tabel frekuensi di atas, harus dapat menentukan seberapa banyak setiap karakter diputar dan teks aslinya.

(Jika Anda tidak terbiasa dengan ROT-n, pada dasarnya mengubah setiap karakter dengan n. Misalnya, dalam ROT-2 a -> c, b -> d, ..., x -> z, y -> a, z -> b,.)

Bagaimana, Anda bertanya? Algoritma (sangat naif) yang harus Anda gunakan adalah:

  • untuk setiap ndari 0ke 25inklusif, menerapkan ROT- -nke string masukan. (Negatif nkarena kami ingin membalik enkripsi. ROT- -nsetara dengan ROT- 26-n, jika itu lebih mudah.)
  • konversi setiap string input ke angka dengan menambahkan frekuensi relatif dari karakter. eis 0, tis 1, ais 2, etc. Misalnya, angka yang sesuai untuk string "hello"adalah 7 + 0 + 10 + 10 + 3 = 30.
  • temukan string yang memiliki angka terkait terendah.
  • output string itu dan yang sesuai n.

Aturan:

  • input bisa masuk akal (STDIN, argumen fungsi, dari file, dll.), dan demikian juga dapat output (STDOUT, nilai pengembalian fungsi, ke file, dll.)
  • Anda dapat menggunakan algoritma yang berbeda, asalkan selalu menghasilkan hasil yang identik. Misalnya, memiliki z0 dan e25 dan memilih angka tertinggi juga oke.
  • jika dua string memiliki skor yang identik, Anda dapat memilih untuk mengeluarkan salah satu (atau keduanya). Ini adalah kasus tepi dan Anda tidak harus menjelaskannya.
  • ini , jadi kode terpendek dalam byte akan menang!

Kasus uji:

Input: ocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvaz
Keluaran:21 thisisaverysecretmessagethatisverysecureandsafe

Input: pmttwxmwxtmwnxzwoziuuqvoxchhtmakwlmowtnabiksmfkpivom
Keluaran:8 hellopeopleofprogrammingpuzzlescodegolfstackexchange

Input: ftueimeqzodkbfqpiuftdaffiqxhqeaufygefnqbqdrqofxkemrq
Keluaran:12 thiswasencryptedwithrottwelvesoitmustbeperfectlysafe

Input: jgtgkuvjghkpcnvguvecugvjcvaqwowuvfgetarv
Keluaran:2 hereisthefinaltestcasethatyoumustdecrypt

Jika Anda bertanya-tanya, ini adalah JSFiddle dari kode uji JavaScript yang saya tulis, yang berhasil mendekripsi semua kasus uji yang saya berikan.


Mungkin berguna untuk mencatat kasus tepi. Misalnya, wtaadharus memberi 0 wtaadsebagai hasilnya, dan vszzcharus memberi 25 wtaadsebagai hasilnya.
mellamokb

Anda harus memberikan poin tambahan untuk mendeteksi implementasi TrippleROT-N.
user19713

@ user19713 Apa itu triplerot? Maksud saya, apa perbedaan antara ROT-6 dan tiga kali ROT-2?
Tn. Lister

2
@ tuan, ini adalah lelucon kripto lama yang mengeluarkan kencing dari TripleDES.
user19713

Bisakah kita mengeluarkan n-root setelah string yang didekripsi?
MayorMonty

Jawaban:


6

GolfScript - 87

Cheat di sini adalah membangun setiap rotasi secara bersamaan. Karena kita perlu mengulang setiap ROT kemudian setiap karakter, mari kita lewati semua karakter, iris seluruh alfabet, lalu rapatkan. Dari sana, lanjutkan seperti yang diharapkan: hitung skor untuk setiap ROT dan pilih minimum.

Golf ekstra:

{97- 26,{97+}%.+''+>}/]{27<}%zip:d{{"etaoinshrdlcumwfgypbvkjxqz"?}%{+}*}%.$0=?.26\-\d=

Hanya sedikit bermain golf:

# the alphabet, and by frequency
26,{97+}%.+''+:a;
"etaoinshrdlcumwfgypbvkjxqz":f;

# build evey ROT decryption
{97-a>}/]{27<}%zip:d

# calculate likelihood
{{f?}%{+}*}%.

# find min
$0=

# output rotation factor and decryption
?.26\-\d=

8

Haskell - 192 175

f y=sum.map(\x->length.fst$break(==x)y)
main=interact(\s->snd$minimum$[(f"etaoinshrdlcumwfgypbvkjxqz"r,show(26-n)++" "++r)|n<-[0..25],let r=map(\x->([x..'z']++['a'..])!!n)s])

Lari

% ./rot-n <<< "pmttwxmwxtmwnxzwoziuuqvoxchhtmakwlmowtnabiksmfkpivom"
8 hellopeopleofprogrammingpuzzlescodegolfstackexchange

Alih-alih menjumlahkan panjang, Anda dapat membentuk daftar yang mewakili angka-angka di unary, misalnya [1,1,1,1], dan ini akan memberikan urutan yang sama. Memetakan dan menjumlahkan kemudian menjadi concatMapyang dapat ditulis secara ringkas menggunakan daftar pemahaman. Dikombinasikan dengan beberapa trik lain, saya menyingkatnya menjadi 152 chars: main=interact(\s->snd$minimum[([1|x<-r,_<-fst$span(/=x)"etaoinshrdlcumwfgypbvkjxqz"],show(26-n)++' ':r)|n<-[0..25],r<-[[([x..'z']++['a'..])!!n|x<-s]]]).
hammar

7

GolfScript, 112 108 102 100 karakter

{{}/]{97-}%}:b~:|;"etaoinshrdlcumwfgypbvkjxqz"b:f,:&,{:x[|{&x-+&%f?}%{+}*\]}%$0=1=:x|{&x-+&%97+}%''+

Saya tidak senang dengan pengulangan dengan mendekripsi ulang pada akhirnya, tapi meh.

Tidak digabungkan (jika itu masuk akal: P) dan versi yang sedikit lebih tua:

# store input IDs (a = 0, b = 1, etc.) in s
[{}/]{97-}%:s;
# store frequency data IDs in f (blah, repetition)
"etaoinshrdlcumwfgypbvkjxqz"[{}/]{97-}%:f

# for each number from 0 to 26 (length of previous string left unpopped)...
,,{
  # the number is x
  :x;
  # return an array of...
  [
    # the score
    s{x 26\-+26%f?}%{+}*
    # and the n
    x
  ]
}%

# use $ort to find the n to output
$0=1=:x

# get the string that the n corresponded to (blah, more repetition)
s{x 26\-+26%97+}%''+

"input bisa masuk akal di mana saja" memang membantu GolfScript. Pada awalnya saya tidak tahu mengapa kedua skrip kami tampaknya mencetak karakter tambahan pada akhirnya, sampai saya sadar echomenempatkan baris baru secara default, yang diambil oleh penerjemah.
sofa dan

6

JavaScript (205)

f='zqxjkvbpygfwmucldrhsnioate';a='abcdefghijklmnopqrstuvwxyz';for(s=prompt(o=m=n=0)
,i=27;i--;w>m&&(m=w,n=i,o=u))for(u='',w=c=0;c<s.length;w+=f.indexOf(x))u+=x=(a+a)[a
.indexOf(s[c++])+i];alert((26-n)+' '+o)

Saya pikir masih bisa bermain golf sedikit lagi, jadi sarannya disambut!

Beberapa catatan membantu memahami solusinya

  • m,, ndan olacak skor tertinggi.
  • udan wmelacak karakter dan hasil nilai, masing-masing untuk saat inii
  • (a+a)membantu mencegah overflow ketika membungkus masa lalu z, dan lebih pendek daripada melakukannya%26
  • Saya memiliki frekuensi dalam urutan terbalik sehingga saya dapat mencari maks, bukan min.

Bukti: http://jsfiddle.net/J9ZyV/5/



4

C # + Linq - 273 264

Sebagai fungsi yang mengambil string input dan mengembalikan string yang di-decode & offset (sesuai kebutuhan):

static Tuple<string,int> d(string s){var r=Enumerable.Range(0,25).Select(i=>string.Concat(from c in s select (char)((c-97+i)%26+97))).OrderBy(x=>(from c in x select "etaoinshrdlcumwfgypbvkjxqz".IndexOf(c)).Sum()).First();return Tuple.Create(r,(s[0]-r[0]+26)%26);}

Tidak dikoleksi dengan komentar:

static Tuple<string,int> d(string s)
{
    var r=Enumerable.Range(0,25)                                               // for every possible offset i
          .Select(i=>string.Concat(from c in s select (char)((c-97+i)%26+97))) // calculate rot_i(input string)
          .OrderBy(                                                            // order these by their score
              x=>(
              from c in x select "etaoinshrdlcumwfgypbvkjxqz".IndexOf(c)       // lookup frequency of each character
              ).Sum()                                                          // and sum each frequency to get the score
           ).First();                                                          // get the first one (lowest score)

    return Tuple.Create(r,(s[0]-r[0]+26)%26);                                  // compute offset and return results
}

Little test driver (ingat untuk mengkompilasi referensi System.Coreuntuk Linq):

using System;
using System.Linq;

namespace codegolf
{
    class Program
    {
        static Tuple<string,int> d(string s){var r=Enumerable.Range(0,25).Select(i=>string.Concat(from c in s select (char)((c-97+i)%26+97))).OrderBy(x=>(from c in x select "etaoinshrdlcumwfgypbvkjxqz".IndexOf(c)).Sum()).First();return Tuple.Create(r,(s[0]-r[0]+26)%26);}

        static void Main(string[] args)
        {
            while (true)
            {
                var input = Console.ReadLine();
                if (input == null) break;
                var retval = d(input);
                Console.WriteLine(String.Format("{0} {1}", retval.Item2, retval.Item1));
            }
        }
    }
}

Memberi:

$ mcs /reference:System.Core.dll main.cs && mono ./main.exe
ocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvaz
21 thisisaverysecretmessagethatisverysecureandsafe
pmttwxmwxtmwnxzwoziuuqvoxchhtmakwlmowtnabiksmfkpivom
8 hellopeopleofprogrammingpuzzlescodegolfstackexchange
ftueimeqzodkbfqpiuftdaffiqxhqeaufygefnqbqdrqofxkemrq
12 thiswasencryptedwithrottwelvesoitmustbeperfectlysafe
jgtgkuvjghkpcnvguvecugvjcvaqwowuvfgetarv
2 hereisthefinaltestcasethatyoumustdecrypt
thisisaverysecretmessagethatisverysecureandsafe
0 thisisaverysecretmessagethatisverysecureandsafe

Saya pikir Anda salah menghitung - solusi Anda saat ini sebenarnya 263 karakter. Anda juga dapat menyimpan satu lagi arang dengan menghapus spasi di antaraTuple<string,int> d
mellamokb

Inilah versi saya yang sangat dekat dalam implementasi tetapi sedikit lebih pendek:Tuple<int,string>f(string x){return Enumerable.Range(0,25).Select(n=>Tuple.Create(26-n,string.Concat(x.Select(c=>(char)((c-97+n)%26+97))))).OrderBy(t=>(t.Item2.Select(c=>"etaoinshrdlcumwfgypbvkjxqz".IndexOf(c))).Sum()).First();}
porges

Saya pikir Anda harus menggunakan Range(0, 26), bukan 25.
Rawling

4

dg - 137 130 129 128 byte

f=t->min key:(t->sum$map 'etaoinshrdlcumwfgypbvkjxqz'.index$snd t)$map(n->n,''.join$map(c->chr$((ord c + 7-n)%26+ 97))t)(0..26)

Contoh:

>>> f 'ocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvaz'
(21, 'thisisaverysecretmessagethatisverysecureandsafe')
>>> f 'pmttwxmwxtmwnxzwoziuuqvoxchhtmakwlmowtnabiksmfkpivom'
(8, 'hellopeopleofprogrammingpuzzlescodegolfstackexchange')
>>> f 'ftueimeqzodkbfqpiuftdaffiqxhqeaufygefnqbqdrqofxkemrq'
(12, 'thiswasencryptedwithrottwelvesoitmustbeperfectlysafe')
>>> f 'jgtgkuvjghkpcnvguvecugvjcvaqwowuvfgetarv'
(2, 'hereisthefinaltestcasethatyoumustdecrypt')

Kode tidak dikunci:

func = t ->
  #: Compute the score of the text `t` with respect to the frequency table.
  #: score :: (int, str) -> int
  score = t ->
    sum $ map 'etaoinshrdlcumwfgypbvkjxqz'.index $ snd t

  #: Compute rot-n of the string `t`. Return the offset and the shifted text.
  #: rot :: int -> (int, str)
  rot = n ->
    n, ''.join $ map (c->chr $ ((ord c + 7 - n) % 26 + 97)) t

  # return the minimum (computed by `score`) amongst all shifted messages
  min key: score $ map rot (0..26)

Tidak bisakah Anda menghapus ruang-ruang itu di sekitar c - 97dan (0..26)?
mniip

Saya hanya bisa menghapus yang kedua. Lakukan sekarang. Saya akan menambahkan beberapa contoh juga.
rubik

1
Belum pernah dengar dgsebelumnya. Bisakah Anda memberikan tautan?
TheDoctor

@TheDoctor: Tentu! pyos.github.io/dg adalah beranda dan pyos.github.com/dg/tutorial tutorial.
rubik

Anda dapat menyimpan satu karakter dengan menambahkan 7 alih-alih mengurangi 97. Modulo 26 mereka adalah hal yang sama.
hammar

4

J - 92 char

Sedikit bebek jelek, tapi berhasil. Menghasilkan angka dan kemudian string, pada dua baris.

(26|](-1!:2&2&.":)(/:'ctljapqhewvknfdsyigbmuoxrz')+/@i."1(i.<./@:)26|(i.-27)+/])&.(_97+3&u:)

Jika Anda ingin mereka berada di jalur yang sama, terpisah ruang, ini hanya mencapai 93 char , tetapi mengambil rute yang lebih buruk.

((":@],[:u:32,97+26|-)(/:'ctljapqhewvknfdsyigbmuoxrz')+/@i."1(i.<./@:)26|(i.-27)+/])@(7+3&u:)

Penjelasan untuk (/:'ctljapqhewvknfdsyigbmuoxrz'): Dalam kata kerja ini, kami beroperasi pada nilai huruf sebagai A = 0, B = 1, C = 2, dll. Untuk menyandikan nilai huruf dari string etaoinshrdlcumwfgypbvkjxqz, cara terpendek sebenarnya adalah dengan mengambil permutasi sortir untuk ini string yang aneh. Ini karena A berada pada indeks 4, B pada indeks 19, C pada 0, D pada 14, dan seterusnya; maka permutasi semacam adalah 4 19 0 14 8 13 ...ketika Anda menilai ( /:) itu, dan Anda mendapatkan nilai angka untuk etaoin....

Pemakaian:

   (26|](-1!:2&2&.":)(/:'ctljapqhewvknfdsyigbmuoxrz')+/@i."1(i.<./@:)26|(i.-27)+/])&.(_97+3&u:) 'ocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvaz'
21
thisisaverysecretmessagethatisverysecureandsafe

   NB. naming for convenience
   f =: (26|](-1!:2&2&.":)(/:'ctljapqhewvknfdsyigbmuoxrz')+/@i."1(i.<./@:)26|(i.-27)+/])&.(_97+3&u:)
   f 'pmttwxmwxtmwnxzwoziuuqvoxchhtmakwlmowtnabiksmfkpivom'
8
hellopeopleofprogrammingpuzzlescodegolfstackexchange
   f 'wtaad'
0
wtaad

3

q, 97

{(w;m w:g?min g:(+/')("etaoinshrdlcumwfgypbvkjxqz"!t)m:(t!u!/:rotate[;u:.Q.a]'[(-)t:(!)26])@\:x)}

.

q) tests:(
    "ocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvazocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvaz";
    "pmttwxmwxtmwnxzwoziuuqvoxchhtmakwlmowtnabiksmfkpivom";
    "ftueimeqzodkbfqpiuftdaffiqxhqeaufygefnqbqdrqofxkemrq";
    "jgtgkuvjghkpcnvguvecugvjcvaqwowuvfgetarv")

q) f:{(w;m w:g?min g:(+/')("etaoinshrdlcumwfgypbvkjxqz"!t)m:(t!u!/:rotate[;u:.Q.a]'[(-)t:(!)26])@\:x)}

q) f each tests
21 "thisisaverysecretmessagethatisverysecureandsafethisisaverysecretmessagethatisverysecureandsafe"
8  "hellopeopleofprogrammingpuzzlescodegolfstackexchange"
12 "thiswasencryptedwithrottwelvesoitmustbeperfectlysafe"
2  "hereisthefinaltestcasethatyoumustdecrypt"

2

APL - 70 karakter

F←{↑⍋+/'etaoinshrdlcumwfgypbvkjxqz'⍳⊃(⍳26){l[(⍺⌽l←⎕UCS 97+⍳26)⍳⍵]}¨⊂⍵}

Contoh:

      F 'ocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvaz'
21
      F 'pmttwxmwxtmwnxzwoziuuqvoxchhtmakwlmowtnabiksmfkpivom'
8
      F 'ftueimeqzodkbfqpiuftdaffiqxhqeaufygefnqbqdrqofxkemrq'
12
      F 'jgtgkuvjghkpcnvguvecugvjcvaqwowuvfgetarv'
2

Saya yakin ada cara untuk mengompres ini lebih lanjut, dan saya mengundang pengguna APL lain untuk mencari solusi untuk itu.


6
Anda harus menampilkan string yang diputuskan juga ...
Gagang Pintu

2

Python 188

x="abcdefghijklmnopqrstuvwxyz"
y=input()
r=lambda n:"".join(x[x.find(i)-n]for i in y)
s={sum("etaoinshrdlcumwfgypbvkjxqz".find(b)for b in r(a)):(a,r(a))for a in range(26)}
print(s[min(s)])

1

Perl: 256 karakter (ditambah baris baru untuk keterbacaan) termasuk tabel frekuensi:

@f=unpack("W*","etaoinshrdlcumwfgypbvkjxqz");
@c=unpack("W*",<>);$m=ord("a");$b=1E10;
for$n(0..25){$s=0;$t="";
for$x(0..scalar@c){$r=($c[$x]-$n-$m)%26+$m;$t.=chr($r);
for(0..scalar@f){if($r==$f[$_]){$s+=$_}}}
if($s<$b){$b=$s;$w=$t;$a=$n}}
printf"%d %s\n",$a,$w;

Teks disediakan seperti ini:

echo "ocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvaz" | perl ./freq.pl 
21 thisisaverysecretmessagethatisverysecureandsafewm

Lepaskan 12 char jika Anda ingin memanggang nilai ord (a) dan panjang @f


1

Elm - 465

Tidak akan memenangkan penghargaan golf apa pun, tetapi itu membuat halaman web statis yang menampilkan daftar formulir [(rotation number, rotated string)] saat Anda mengetik.

Catatan: belum bekerja di sini tetapi Anda dapat menyalin-menempelkannya ke editor resmi dan menjalankannya.

import String as S
import Char (..)
import Graphics.Input (..)
import Graphics.Input.Field (..)
f="ETAOINSHRDLCUMWFGYPBVKJXQZ"
r s n=let t c=mod(toCode c-65+n)26+65 in map(fromCode . t)(S.toList s)
w s=case s of 
 ""->0
 s->sum(S.indexes(S.left 1 s)f)+w(S.dropLeft 1 s)
b s=sort<|map(\x->((w . S.fromList . r s)x,(26-x,S.fromList<|r s x)))[0..25]
c=input noContent
main=above<~(field defaultStyle c.handle id""<~c.signal)~(asText . b . .string<~c.signal)

1

Python 2, 171

f,R,i='zqxjkvbpygfwmucldrhsnioate',{},raw_input();a=sorted(f)*2
for n in range(26):_=''.join(a[ord(x)-71-n]for x in i);R[sum(2**f.index(x)for x in _)]=n,_
print R[max(R)]
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.