Что это за ROT? - расшифровать ROT-N


25

Вот буквы английского алфавита по порядку по частоте:

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

Это eнаиболее часто используемая буква и zнаименее распространенная. (Данные из Википедии .)

Ваша задача - взять текст ROT-n'd, например:

ocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvaz

Это текст «это очень секретное сообщение, которое очень надежный и безопасный», который «зашифрован» через ROT-21 (половина из 42). Ваша программа, используя приведенную выше таблицу частот, должна быть в состоянии определить, насколько повернут каждый символ и исходный текст.

(Если вы не знакомы с ROT-n, он по существу сдвигает каждый символ на n. Например, в ROT-2,. a -> c, b -> d, ..., x -> z, y -> a, z -> b)

Как, спросите вы? (Очень наивный) алгоритм, который вы должны использовать:

  • для каждого nот 0до 25включительно применять ROT- -nк входной строке. (Отрицательно, nпотому что мы хотим изменить шифрование. ROT- -nэквивалентно ROT- 26-n, если это проще.)
  • преобразовать каждую входную строку в число, сложив относительные частоты символов. eis 0, tis 1, ais 2и т. д. Например, соответствующее число для строки "hello"7 + 0 + 10 + 10 + 3 = 30.
  • найти строку с наименьшим соответствующим номером.
  • выведите эту строку и соответствующую ей n.

Правила:

  • ввод может быть в любом месте (STDIN, аргументы функции, из файла и т. д.), и поэтому может выводить (STDOUT, возвращаемое значение функции в файл и т. д.)
  • Вы можете использовать другой алгоритм, если он всегда дает одинаковые результаты. Например, zиметь 0 и e25 и выбирать наибольшее число тоже нормально.
  • если две строки имеют одинаковые оценки, вы можете выбрать выводить одну (или обе) из них. Это крайний случай, и вы не обязаны это учитывать.
  • это , поэтому выиграет самый короткий код в байтах!

Тестовые случаи:

Вход: ocdndnvqzmtnzxmzohznnvbzocvodnqzmtnzxpmzviynvaz
Выход:21 thisisaverysecretmessagethatisverysecureandsafe

Вход: pmttwxmwxtmwnxzwoziuuqvoxchhtmakwlmowtnabiksmfkpivom
Выход:8 hellopeopleofprogrammingpuzzlescodegolfstackexchange

Вход: ftueimeqzodkbfqpiuftdaffiqxhqeaufygefnqbqdrqofxkemrq
Выход:12 thiswasencryptedwithrottwelvesoitmustbeperfectlysafe

Вход: jgtgkuvjghkpcnvguvecugvjcvaqwowuvfgetarv
Выход:2 hereisthefinaltestcasethatyoumustdecrypt

Если вам интересно, вот JSFiddle из написанного мной тестового кода JavaScript, который успешно расшифровал все тестовые примеры, которые я к нему применил.


Может быть полезно отметить крайние случаи. Например, wtaadдолжен давать 0 wtaadкак результат, и vszzcдолжен давать 25 wtaadкак результат.
mellamokb

Вам следует дать дополнительные баллы за обнаружение внедрения TrippleROT-N.
user19713

@ user19713 Что такое triplerot? Я имею в виду, в чем разница между ROT-6 и трехкратным ROT-2?
Мистер Листер

2
@mrlister это старая криптографическая шутка, которая выводит из себя TripleDES.
user19713

Можем ли мы вывести n-корень после расшифрованной строки?
MayorMonty

Ответы:


6

GolfScript - 87

Обман здесь, чтобы построить каждое вращение одновременно. Поскольку нам нужно циклически проходить каждый ROT, то каждый символ, давайте просто зациклим каждый символ, нарежем весь алфавит, а затем сожмем его. Оттуда действуйте, как и ожидалось: подсчитайте баллы для каждого ROT и выберите минимум.

Дополнительный гольф:

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

Только немного в гольф:

# 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])

Бег

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

Вместо суммирования длин вы можете сформировать списки, представляющие числа в унарном виде, например [1,1,1,1], и это даст тот же порядок. Затем происходит сопоставление и суммирование, concatMapкоторые можно записать кратко, используя понимание списка. В сочетании с некоторыми другими трюками, я укоротил до 152 символов: 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]]]).
хаммар

7

GolfScript, 112 108 102 100 символов

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

Я не рад повторению с повторным расшифровыванием в конце, но ме.

Ungolfed (если это имеет смысл: P) и немного более старая версия:

# 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+}%''+

«Ввод может быть где угодно» помогает GolfScript. Сначала я не мог понять, почему оба наших скрипта, казалось, печатали дополнительный символ в конце, пока не понял, echoчто по умолчанию ставит новую строку, которую переводчик подхватывает.
Каучанд

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)

Я думаю, что все еще можно играть в гольф немного больше, поэтому предложения приветствуются!

Некоторые примечания, чтобы помочь понять решение

  • m, n И oотслеживать самые высокие оценки.
  • u а также w отслеживать символ и значение результата, соответственно для текущегоi
  • (a+a) помогает предотвратить переполнение при обтекании z и короче, чем выполнение%26
  • У меня есть частота в обратном порядке, поэтому я могу искать максимум вместо мин.

Доказательство: http://jsfiddle.net/J9ZyV/5/



4

C # + Linq - 273 264

Как функция, которая принимает входную строку и возвращает декодированную строку и смещение (согласно требованиям):

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

Маленький тестовый драйвер (не забудьте скомпилировать ссылки System.Coreдля 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));
            }
        }
    }
}

Предоставление:

$ 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

Я думаю, что вы ошиблись - ваше текущее решение на самом деле составляет 263 символа. Также вы можете сохранить еще один символ, убрав пробел междуTuple<string,int> d
mellamokb

Вот моя версия, которая очень близка по реализации, но немного короче: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

Я думаю, что вы должны использовать Range(0, 26), а не 25.
Роулинг

4

дг - 137 130 129 128 байт

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)

Примеры:

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

Ungolfed код:

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)

Разве вы не можете удалить эти места вокруг c - 97и (0..26)?
Мниип

Я могу удалить только второй. Делаю это сейчас. Я также добавлю несколько примеров.
Рубик

1
Никогда не слышал dgраньше. Не могли бы вы предоставить ссылку?
TheDoctor

@TheDoctor: Конечно! pyos.github.io/dg - это домашняя страница, а pyos.github.com/dg/tutorial - учебник.
Рубик

Вы можете сохранить один символ, добавив 7 вместо вычитания 97. По модулю 26 это одно и то же.
Хаммар

4

J - 92 символа

Немного гадкого утенка, но это работает. Выводит число, а затем строку в две строки.

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

Если вы хотите, чтобы они находились на одной линии, разделенные пробелами, это только увеличит до 93 символов , но пойдет по более уродливому маршруту.

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

Объяснение для (/:'ctljapqhewvknfdsyigbmuoxrz'): В этом глаголе мы оперируем буквенными значениями как A = 0, B = 1, C = 2 и т. Д. Чтобы закодировать буквенные значения строки etaoinshrdlcumwfgypbvkjxqz, самый короткий путь - фактически принять перестановку сортировки для этого странная строка Это связано с тем, что A имеет индекс 4, B - индекс 19, C - 0, D - 14 и т. Д .; следовательно, перестановка сортировки - это 4 19 0 14 8 13 ...когда вы оцениваете /:ее, и вы получаете точно числовые значения для etaoin....

Использование:

   (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 символов

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

Пример:

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

Я уверен, что есть способы сжимать это дальше, и я приглашаю всех других пользователей APL придумать решения для этого.


6
Вы должны вывести определенную строку тоже ...
Дверная ручка

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 символов (плюс новые строки для удобства чтения), включая таблицу частот:

@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;

Текст предоставляется так:

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

Снимите 12 символов, если хотите запечь значения ord (a) и длину @f


1

Вяз - 465

Не собираюсь выигрывать какие-либо награды в гольфе, но он создает статическую веб-страницу, которая отображает список форм по [(rotation number, rotated string)]мере ввода.

Примечание: здесь еще не работает, но вы можете скопировать и вставить его в официальный редактор и запустить его.

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)]
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.