Бінарне шифрування


11

Це засновано на xkcd # 153 .

Створіть програму або названу функцію, яка приймає 2 параметри, кожен з яких - це рядок або список або масив байтів або символів. Другий параметр буде містити лише символи, отримані з lrfu(або еквівалентних байтів ASCII). Це слід інтерпретувати як серію інструкцій, що виконуються на бітовій послідовності, представленій першим параметром.

Виконана обробка повинна бути еквівалентною наступному:

  1. Перетворіть перший параметр в єдиний бітовий рядок, утворений об'єднанням бітів кожного символу (інтерпретується як один із 7-бітових ASCII, 8-бітний розширений ASCII або стандартне кодування Unicode). Наприклад, якщо перший параметр є, "AB"то це буде один із 10000011000010(7-бітових), 0100000101000010(8-бітових або UTF-8) 00000000010000010000000001000010, або 01000001000000000100001000000000(UTF-16 у двох обставинах) тощо.
  2. Для кожного символу другого параметра для того, щоб виконати відповідну інструкцію:
    • lобертає бітне рядок зліва. Напр. 10000011000010Стає 00000110000101.
    • rобертає біткорд праворуч. Напр. 10000011000010Стає 01000001100001.
    • fперевертає (або перевертає) кожен біт у шматочку. Напр. 10000011000010Стає 01111100111101.
    • uобертає біткорд. Напр. 10000011000010Стає 01000011000001.
  3. Перетворіть біткорд в рядок ASCII, в якому використовується один символ на біт. Напр. 10000011000010Стає "10000011000010". Це тому, що не всі набори 7/8 біт мають призначений їм символ.

Приклад (в Python):

>>> f("b", "rfu")
01110011

Він перетворюється "b"на 8-бітове двійкове представлення ASCII 01100010, обертає його праворуч ( 00110001), перевертає кожен біт ( 11001110) і повертає його назад ( 01110011).

Гнучкість

Інші символи можуть бути використані замість символів l, r, fі u, але вони повинні бути чітко задокументовані.

Табло

Дякуємо @Optimizer за створення наступного фрагмента коду. Для використання натисніть «Показати фрагмент коду», прокрутіть донизу та натисніть «► Запустити фрагмент коду».


3
Яким може бути другий параметр? Чи може бути "rrfrburb"? Крім того, коли один змінює або повертає біти, чи робить це для кожної окремої літери чи рядка в цілому? Більше тестових випадків зробить це зрозумілішим.
xnor

1
Ви маєте на увазі зсув чи поворот? лівий зсув у C призведе до втрати крайнього лівого біта, а самий правий біт стане нульовим. Для зміни прав на ненаписаний номер відбувається зворотне. Що стосується підписаного номера, я не впевнений, чи існує універсально визначена поведінка щодо того, що переміщується за негативними числами (це 0 або 1?), Так чи інакше, інформація завжди втрачається при здійсненні зміни, що не так для обертання.
Річка Рівня Св.


2
@flawr, я не думаю, що це матиме якусь перевагу над існуючою можливістю пошуку "xkcd"
Пітер Тейлор

1
@KSFT Я думаю, що мені доведеться сказати "ні". Зробіть це рядок, приєднавшись до нього.

Відповіді:


1

CJam, 34 32 байти

1l+256b2b1>l{~"11W:mm%!<>">4%~}/

Для використання в ньому використовуються такі символи:

0: left rotation
1: right rotation
2: reverse
3: flip

Вхід береться від STDIN зі словом у першому рядку та рядком інструкцій у другому рядку.

Тестуйте це тут.

Пояснення

Отримати бітовий рядок - це справді лише питання інтерпретації символьних кодів як цифр базового числа 256 (та отримання його представлення base-2). Найскладніша річ у тому, що остання конверсія бази не підкреслить результат з 0 зліва. Тому я додаю ведучий 1 до початкового вводу, а потім знову розбиваю цей 1 у двійковому поданні. Як приклад, якщо вхід є ab, я перетворюю це на масив [1 'a 'b], інтерпретую це як base-256 (символи автоматично перетворюються на коди символів), що є 90466і як base-2, що є [1 0 1 1 0 0 0 0 1 0 1 1 0 0 0 1 0]. Тепер, якщо я просто 1видаляю цю ведучу, я отримав біткойн, який я шукаю.

Ось що робить ця частина коду:

1l+256b2b1>

Тепер я читаю список інструкцій і виконую блок для кожного символу в рядку інструкцій:

l{...}/

Перше , що потрібно зробити , це оцінити характер і дійсні цілі числа 0, 1, 2або 3. Тепер справжня магія гофри ... залежно від інструкції я хочу запустити короткий фрагмент коду, який реалізує операцію:

Integer:  Code  Operation
0         1m<   "Left rotation";
1         1m>   "Right rotation";
2         W%    "Reverse";
3         :!    "Flip each bit";

Я міг би зберігати їх у масиві блоків і вибирати правильний блок для запуску, але кодування їх у рядку насправді коротше:

"11W:mm%!<>">4%~

По-перше, я використовую асоційоване ціле число з інструкцією, щоб відрізати початок рядка. Отже, для лівого обертання рядок є незмінною, для правого обертання перший символ відкидається тощо. Потім я вибираю кожен четвертий символ із рядка, починаючи з першого, з 4%. Зауважте, як чотири фрагменти коду розподіляються по рядку. Нарешті я просто оцінюю рядок як код ~.

Рядок бітів друкується автоматично в кінці програми.


Чому, 1m<а не (+? Ви працюєте над масивом, а не числом, чи не так?
Пітер Тейлор

@ Петер о так, дякую. Я це виправлю пізніше.
Мартін Ендер

2

CJam, 34 байти

Ще один підхід у CJam.

1l+256b2b1>l_S/,1&@f=_,,@f{W%~}\f=

Текст введення знаходиться в першому рядку, а вказівки - у другому рядку.

Інструкції:

)        Rotate left.
(        Rotate right.
 (space) Flip.
~        Reverse.

1
Це досить розумно. Сором, який f~не реалізується, чи не так? ;)
Мартін Ендер

2

Піт 33

jku@[+eGPG+tGhG_Gms!dG)sHwsmjCk2z

Використання:

0    : rotate right
1    : rotate left
2    : reverse order
3    : flip values

Піт-гітуб

Спробуйте його онлайн тут.

Це програма, яка приймає рядок як перший аргумент, а рядок команд - як другий аргумент. В онлайн-версії слід вказати рядки, розділені новим рядком, як-от так:

AbC
0321

Пояснення:

                                    : z=input() (implicit)
jk                                  : join("", ...)
  u@[                 )sHw          : reduce(select from [...] the value at int(H), input(), ...)
     +eGPG                          : [ G[-1] + G[:1],
          +tGhG                     : G[1:] + G[1],
               _G                   : G[::-1],
                 ms!dG              : map(lambda d: int(not(d)), G) ]
                          smjCk2z   : first arg = sum(map(lambda k:convert_to_base(ord(k),2),z)

Щось я не міг цілком стиснути: Pyth's reduceавтоматично використовує як Gдля попереднього, так і Hдля наступного значення.


Втратити свій дотик? Всього на 1 байт коротше, ніж CJam?
Оптимізатор

@Optimizer Насправді я можу це перемогти, використовуючи ті самі інструкції. Але я не вважав, що це буде справедливим, тому що у виклику сказано: "Інші листи можуть використовуватися замість lrfu, але вони повинні бути чітко зафіксовані". (наголос мій)
Мартін Ендер

1

Scala - 192

def f(i:String,l:String)=(i.flatMap(_.toBinaryString).map(_.toInt-48)/:l){
case(b,'l')⇒b.tail:+b.head
case(b,'r')⇒b.last+:b.init
case(b,'f')⇒b.map(1-_)
case(b,'u')⇒b.reverse}.mkString

1

Matlab (166 байт)

Для цього використовуються літери abcdзамість lrfuвідповідно.

function D=f(B,C)
D=dec2bin(B,8)';
D=D(:);
g=@circshift;
for c=C
switch c-97
case 0
D=g(D,-1);
case 1
D=g(D,1);
case 2
D=char(97-D);
case 3
D=flipud(D);
end
end
D=D';

Деякі хитрощі, які використовуються тут для економії місця:

  • Використання abcdбукв дозволяє мені вичитати 97один раз, а потім листи стали 0, 1, 2, 3. Це економить місце в пунктах switch- case.
  • Визначення circshiftяк анонімної функції з однієї літери також економить місце, оскільки вона використовується двічі.
  • Оскільки Dскладається з '0'і '1'символів (ASCII коди 48і 49), твердження D=char(97-D)відповідає інверсії між '0'і '1'значеннями. Зауважте, що це не 97має нічого спільного з вищезгаданим.
  • Комплекс-кон'югат транспозиції 'використовується замість транспозиції .'.

0

Пітон 2 - 179

b="".join([bin(ord(i))[2:]for i in input()])
for i in input():b=b[-1]+b[:-1]if i=="r"else b[1:]+b[0]if i=="l"else[str("10".find(j))for j in b]if i=="f"else b[::-1]
print"".join(b)

0

C #, 418 байт

using System;using System.Collections.Generic;using System.Linq;class P{string F(string a,string o){var f=new Dictionary<char,Func<string,IEnumerable<char>>>{{'l',s=>s.Substring(1)+s[0]},{'r',s=>s[s.Length-1]+s.Substring(0,s.Length-1)},{'u',s=>s.Reverse()},{'f',s=>s.Select(c=>(char)(97-c))}};return o.Aggregate(string.Join("",a.Select(c=>Convert.ToString(c,2).PadLeft(8,'0'))),(r,c)=>new string(f[c](r).ToArray()));}}

Відформатовано:

using System;
using System.Collections.Generic;
using System.Linq;

class P
{
    string F(string a, string o)
    {
        // define string operations
        var f = new Dictionary<char, Func<string, IEnumerable<char>>>
        {
            {'l', s => s.Substring(1) + s[0]},
            {'r', s => s[s.Length - 1] + s.Substring(0, s.Length - 1)},
            {'u', s => s.Reverse()},
            {'f', s => s.Select(c => (char) (97 - c))}
        };
        // for each operation invoke f[?]; start from converted a
        return o.Aggregate(
            // convert each char to binary string, pad left to 8 bytes and join them
            string.Join("", a.Select(c => Convert.ToString(c, 2).PadLeft(8, '0'))),
            // invoke f[c] on result of prev operation
            (r, c) => new string(f[c](r).ToArray())
        );
    }
}

0

J, 164

([: >@:}. (([: }. >&{.) ; >@:{.@:>@:{. 128!:2 >@:}.)^:({.@:$@:>@:{.))@:(>@:((<;._1 ' 1&|."1 _1&|."1 -. |."1') {~ 'lrfu' i. 0&({::)@:]) ; ;@:([: (8$2)&#: a. i. 1&({::)))

Відформатовано:

nextop=:([: }. >&{.)
exec=: (>@:{.@:>@:{.) apply"1 >@:}.
times=: ({.@:$@:>@:{.)
gapply=: [: >@:}. (nextop ; exec)^:(times) f.

tobin=: ;@:([: (8#2)&#:(a.i.1&{::))
g=:'1&|.';'_1&|.';'-.';'|.'
tog =:  g {~ ('lrfu' i. 0&{::@:])
golf=: gapply @: (>@:tog;tobin)  f.

Приклад

golf ('rfu';'b')
0 1 1 1 0 0 1 1


golf ('lruuff';'b')
0 1 1 0 0 0 1 0

(8#2)#: 98
0 1 1 0 0 0 1 0

golf ('lruuff';'AB')
0 1 0 0 0 0 0 1 0 1 0 0 0 0 1 0

tobin '';'AB'
0 1 0 0 0 0 0 1 0 1 0 0 0 0 1 0

0

JavaScript (E6), 163 167

Повністю використовуючи вхідну гнучкість, названу функцію з 2 параметрами масиву.

  • Перший параметр - масив байтів, що відповідає 7-ти бітовим символьним кодам
  • Другий параметр, масив байтів, що відповідає символам ascii 'F', 'L', 'R', 'U' -> 70, 76, 82, 85

Функція повертає символьний рядок, що складається з '1' і '0'

F=(a,s,r='')=>
  a.map(c=>r+=(128|c).toString(2).slice(-7))-
  s.map(c=>a=c<71?a.map(c=>1-c):c<77?a.concat(a.shift):c<83?[a.pop(),...a]:a.reverse(),a=[...r])
  ||a.join('')

Приклад f("b", "rfu") перекладати на F([98],[82,70,85]), результат є0111001

Зауважте, що використання символьних рядків у JavaScript набагато довше! Кількість байтів 186

F=(a,s,r='')=>
  [for(c of a)r+=(128|c.charCodeAt()).toString(2).slice(-7)]-
  [for(c of(a=[...r],s))a=c<'G'?a.map(c=>1-c):c<'M'?a.concat(a.shift):c<'S'?[a.pop(),...a]:a.reverse()]
  ||a.join('')

Приклад F("b", "RFU") , результат 0111001знову


0

Рубі, 151

f=->i,s{s.chars.inject(i.unpack("B*")[0]){|a,c|
a.reverse! if c==?u
a.tr!"01","10" if c==?f
a<<a.slice!(1..-1) if c==?l
a<<a.slice!(0..-2) if c==?r
a}}

Досить прямо. Петля проходить через символів sі виконує дію для будь-якого з них.


0

Пітон 2, 142

j="".join
f=lambda S,I:reduce(lambda s,i:[s[1:]+s[0],s[-1]+s[:-1],s[::-1],j([`1^int(c)`for c in s])][int(i)],I,j([bin(ord(c))[2:]for c in S]))

Аналогічно моїй відповіді pyth у підході: я будую список усіх рядків та індексую його на основі значення рядка інструкцій, який я повторюю за допомогою зменшення.

Використання:

0  ->  Rotate left
1  ->  Rotate right
2  ->  Reverse order
3  ->  Invert bits
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.