Binäre Verschlüsselung

11

Dies basiert auf xkcd # 153 .

Erstellen Sie ein Programm oder eine benannte Funktion, die zwei Parameter akzeptiert, von denen jeder eine Zeichenfolge oder eine Liste oder ein Array von Bytes oder Zeichen ist. Der zweite Parameter enthält nur Zeichen lrfu(oder die entsprechenden ASCII-Bytes). Es sollte als eine Reihe von Anweisungen interpretiert werden, die an einer durch den ersten Parameter dargestellten Bitfolge ausgeführt werden sollen.

Die durchgeführte Verarbeitung muss der folgenden entsprechen:

  1. Konvertieren Sie den ersten Parameter in einen einzelnen Bitstring, der durch Verketten der Bits jedes Zeichens gebildet wird (interpretiert als einer von 7-Bit-ASCII, einem 8-Bit-erweiterten ASCII oder einer Standard-Unicode-Codierung). Wenn beispielsweise der erste Parameter lautet, "AB"ist dies einer von 10000011000010(7-Bit), 0100000101000010(8-Bit oder UTF-8) 00000000010000010000000001000010oder 01000001000000000100001000000000(UTF-16 in den beiden Endiannessen) usw.
  2. Führen Sie für jedes Zeichen im zweiten Parameter der Reihe nach die entsprechende Anweisung aus:
    • ldreht den Bitstring nach links. ZB 10000011000010wird 00000110000101.
    • rdreht den Bitstring nach rechts. ZB 10000011000010wird 01000001100001.
    • fkippt (oder invertiert) jedes Bit in der Bitfolge. ZB 10000011000010wird 01111100111101.
    • ukehrt die Bitfolge um. ZB 10000011000010wird 01000011000001.
  3. Konvertieren Sie den Bitstring in einen ASCII-String, der ein Zeichen pro Bit verwendet. ZB 10000011000010wird "10000011000010". Dies liegt daran, dass nicht allen Sätzen von 7/8 Bits ein Zeichen zugewiesen ist.

Beispiel (in Python):

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

Es verwandelt sich "b"in seine 8-Bit-ASCII-Binärdarstellung 01100010, dreht es nach rechts ( 00110001), dreht jedes Bit ( 11001110) um und kehrt es um ( 01110011).

Flexibilität

Andere Zeichen anstelle der Zeichen verwendet werden können l, r, f, und u, aber sie müssen eindeutig dokumentiert werden.

Anzeigetafel

Vielen Dank an @Optimizer für die Erstellung des folgenden Code-Snippets. Klicken Sie zur Verwendung auf "Code-Snippet anzeigen", scrollen Sie nach unten und klicken Sie auf "► Code-Snippet ausführen".


quelle
3
Was kann der zweite Parameter sein? Kann es sein "rrfrburb"? Wenn man Bits verschiebt oder umkehrt, macht man das auch für jeden einzelnen Buchstaben oder die Zeichenfolge als Ganzes? Weitere Testfälle würden es klarer machen.
xnor
1
Meinst du verschieben oder drehen? Eine Linksverschiebung in C führt dazu, dass das Bit ganz links verloren geht und das Bit ganz rechts Null wird. Bei einer Rechteverschiebung bei einer vorzeichenlosen Nummer geschieht das Gegenteil. Bei einer vorzeichenbehafteten Zahl bin ich mir nicht sicher, ob es ein allgemein definiertes Verhalten für das gibt, was für negative Zahlen verschoben wird (ist es 0 oder 1?). In beiden Fällen gehen Informationen immer verloren, wenn eine Verschiebung durchgeführt wird, was nicht der Fall ist für eine Drehung.
Level River St
2
FWIW gibt es bereits eine Frage, die auf dieser XKCD basiert .
Peter Taylor
2
@flawr, ich glaube nicht, dass es einen Vorteil gegenüber der bestehenden Fähigkeit hätte, nach 'xkcd'
Peter Taylor
1
@KSFT Ich denke, ich muss nein dazu sagen. Machen Sie daraus einen String, indem Sie ihn verbinden.

Antworten:

1

CJam, 34 32 Bytes

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

Für Anweisungen werden die folgenden Zeichen verwendet:

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

Die Eingabe erfolgt von STDIN mit dem Wort in der ersten Zeile und der Anweisungszeichenfolge in der zweiten Zeile.

Testen Sie es hier.

Erläuterung

Das Abrufen der Bitfolge ist eigentlich nur eine Frage der Interpretation der Zeichencodes als Ziffern einer Basis-256-Zahl (und des Abrufs ihrer Basis-2-Darstellung). Das Schwierige ist, dass die letztere Basiskonvertierung das Ergebnis nicht mit Nullen auf der linken Seite auffüllt. Daher füge ich der anfänglichen Eingabe eine führende 1 hinzu und spalte diese 1 dann in der Binärdarstellung erneut ab. Als ein Beispiel, wenn der Eingang ist ab, I wiederum , dass in einer Anordnung [1 'a 'b], interpretieren , dass als Base-256 (Zeichen automatisch in Zeichencodes umgewandelt werden), der 90466und der zur Basis 2, die ist [1 0 1 1 0 0 0 0 1 0 1 1 0 0 0 1 0]. Wenn ich jetzt nur diese Leitung entferne, 1habe ich den Bitstream, den ich suche.

Das macht dieser Teil des Codes:

1l+256b2b1>

Jetzt lese ich die Liste der Anweisungen und führe einen Block für jedes Zeichen in der Anweisungszeichenfolge aus:

l{...}/

Das erste , was zu tun ist , den Charakter und die tatsächlichen Zahlen zu bewerten 0, 1, 2oder 3. Nun die wahre Golfmagie ... Abhängig von der Anweisung möchte ich einen kurzen Code ausführen, der die Operation implementiert:

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

Ich könnte diese in einem Array von Blöcken speichern und den richtigen Block zum Ausführen auswählen, aber das Codieren in einer Zeichenfolge ist tatsächlich kürzer:

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

Zuerst verwende ich die mit der Anweisung verknüpfte Ganzzahl, um den Anfang der Zeichenfolge abzuschneiden. Bei Linksdrehung bleibt die Zeichenfolge unverändert, bei Rechtsdrehung wird das erste Zeichen verworfen und so weiter. Dann wähle ich jedes vierte Zeichen aus der Zeichenfolge aus, beginnend mit dem ersten, mit 4%. Beachten Sie, wie die vier Codefragmente in der Zeichenfolge verteilt sind. Zum Schluss bewerte ich den String einfach als Code mit ~.

Die Bitfolge wird am Ende des Programms automatisch gedruckt.

Martin Ender
quelle
Warum 1m<eher als (+? Sie arbeiten eher an einem Array als an einer Zahl, nicht wahr?
Peter Taylor
@ Peter oh richtig, danke. Ich werde das später beheben.
Martin Ender
2

CJam, 34 Bytes

Ein anderer Ansatz in CJam.

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

Der Eingabetext befindet sich in der ersten Zeile und die Anweisungen in der zweiten Zeile.

Anleitung:

)        Rotate left.
(        Rotate right.
 (space) Flip.
~        Reverse.
jimmy23013
quelle
1
Das ist ziemlich klug. Eine Schande, die f~aber nicht umgesetzt wird, oder? ;)
Martin Ender
2

Pyth 33

jku@[+eGPG+tGhG_Gms!dG)sHwsmjCk2z

Verwendet:

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

Pyth Github

Probieren Sie es hier online aus.

Dies ist ein Programm, das die Zeichenfolge als erstes Argument und die Befehlszeichenfolge als zweites Argument verwendet. In der Online-Version sollten Sie die Zeichenfolgen durch einen Zeilenumbruch trennen, wie folgt:

AbC
0321

Erläuterung:

                                    : 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)

Etwas, in das ich mich nicht ganz hineinquetschen konnte: Pyth's verwendet reduceautomatisch Gfür den vorherigen Wert und Hfür den nächsten Wert.

FryAmTheEggman
quelle
Deine Berührung verlieren? Nur 1 Byte kürzer als CJam?
Optimierer
@Optimizer Eigentlich kann ich das mit den gleichen Anweisungen übertreffen. Aber ich dachte nicht, dass dies gültig wäre, da die Herausforderung besagt: "Andere Buchstaben können anstelle von verwendet werden lrfu, aber sie müssen klar dokumentiert werden." (Hervorhebung von mir)
Martin Ender
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
Gilad hoch
quelle
1

Matlab (166 Bytes)

Dies verwendet Buchstaben abcdanstelle von lrfujeweils.

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

Einige hier verwendete Tricks, um Platz zu sparen:

  • Mit abcdBuchstaben läßt mich subtrahieren 97einmal, und dann die Buchstaben werden 0, 1, 2, 3. Dies spart Platz in den switch- caseKlauseln.
  • Das Definieren circshiftals anonyme Ein-Buchstaben-Funktion spart außerdem Platz, da sie zweimal verwendet wird.
  • Da es Daus '0'und '1'Zeichen (ASCII-Codes 48und 49) besteht, entspricht die Anweisung D=char(97-D)der Inversion zwischen '0'und '1'Werten. Beachten Sie, dass dies 97nichts mit dem oben genannten zu tun hat.
  • Komplex-konjugierte Transponierung 'wird anstelle von Transponierung verwendet .'.
Luis Mendo
quelle
0

Python 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)
KSFT
quelle
0

C #, 418 Bytes

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()));}}

Formatiert:

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())
        );
    }
}
Krzysztof
quelle
0

J, 164

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

Formatiert:

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.

Beispiel

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
Joebo
quelle
0

JavaScript (E6), 163 167

Vollständige Nutzung der Eingabeflexibilität, eine benannte Funktion mit 2 Array-Parametern.

  • Erster Parameter, Array von Bytes, die 7-Bit-Zeichencodes entsprechen
  • Zweiter Parameter, Array von Bytes, die den ASCII-Zeichen 'F', 'L', 'R', 'U' -> 70, 76, 82, 85 entsprechen

Die Funktion gibt eine Zeichenfolge zurück, die aus '1' und '0' besteht.

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('')

Beispiel f("b", "rfu") übersetzen in F([98],[82,70,85]), Ergebnis ist0111001

Beachten Sie, dass die Verwendung von Zeichenfolgen in Javascript viel länger dauert! Bytezahl 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('')

Beispiel F("b", "RFU") , Ergebnis ist 0111001wieder

edc65
quelle
0

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

Ziemliech direkt. Schleifen durch die Charaktere sund führen eine Aktion für einen von ihnen aus.

britishtea
quelle
0

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

Ähnlich wie bei meiner Python-Antwort im Ansatz: Ich erstelle eine Liste aller Zeichenfolgen und indiziere sie basierend auf dem Wert der Anweisungszeichenfolge, die ich mit reduct iteriere.

Verwendet:

0  ->  Rotate left
1  ->  Rotate right
2  ->  Reverse order
3  ->  Invert bits
FryAmTheEggman
quelle