A substitution cipher is an encoding method where each letter in the alphabet is replaced with a fixed, different one; for example, given the following substitution map:


The phrase "we all love cryptography" would be encoded as "vt qss sgct eknhzgukqhin".

The program will continuously read its input, one line at time; the first line will contain the substitution map, in the form of all 26 letters, in any order, without repetitions, missing letters or extraneous characters; it will be interpreted as "the first letter is the substitution for A, the second letter is the substitution for B [...] the 26th letter is the substitution for Z"; no output will be provided after reading it. For each subsequent line, the program will output the encoded text corresponding to the line. Only letters will be encoded; numbers, symbols and whitespaces will be simply copied to the output.

For simplicity, all input (including the substitution map) will only contain lowercase characters.

Sample input:

i don't know.

Sample output:

o rgf'z afgv.

As usual, the shortest solution wins.

Additional clarifications on input:

  • The program must read its input stream (I thought that was clear); command line parameters, files, named pipes, network sockets, quantum entanglement or extra sensorial perceptions are not allowed.
  • The input must include only the actual text to be processed; quotes, brackets, commas or any other symbol, if found, should simply be copied to the output as they are.
  • No additional characters should be required in the input. If your program requires the input text to be placed in quotes, brackets, commas or any other delimiter, then You Are Doing It Wrong (TM).
  • "Line" is defined as a string of characters followed by a newline; the actual implementation of "newline" if usually left to the OS, but if you need to go into its details, just use whatever you prefer.
  • An empty line is no special case; the program could either print an empty line or do nothing, but it should not print any actual text, crash, exit, destroy the operating system, set fire to the house, collapse the Sun in a black hole, summon demons from other planes of existence or replace your toothpaste with mayonnaise.
  • There is no requirement for the program to run interactively; it's free to suck all its input in and then print all its output; there is also not any time limit on its execution, although it would be definitely preferable for it to terminate before the heat death of the universe.
  • 1
    \$\begingroup\$ @LuisMendo If the program exits with a crash after the input is exhausted and the correct output is procuced, then yes, it's ok. \$\endgroup\$ – Massimo Apr 16 '16 at 0:56
  • 11
    \$\begingroup\$ @Massimo Arbitrarily overriding the defaults by not allowing a function and requiring a cumbersome input format are both considered things to avoid. The rules are ultimately up to you, but don't be surprised to get downvotes if your the community believes your challenge needlessly restricts participation. Note that some languages simply cannot do IO loops. \$\endgroup\$ – xnor Apr 16 '16 at 4:25
  • 6
    \$\begingroup\$ @Massimo Furthermore, saying thing like "If your program requires the input text to be placed in quotes, brackets, commas or any other delimiter, then You Are Doing It Wrong (TM)" is needlessly confrontational and contrarian, as the community has discussed and decided to allow such things in general. Again, you can override them, but expect a poor reaction, as there seems to be no good reason. Perhaps you have experience with other golfing sites that do expect exact inputs, but that's not how we work around here. I suggest you stick around a bit and get a sense of the usual rules and culture. \$\endgroup\$ – xnor Apr 16 '16 at 4:28
  • 7
    \$\begingroup\$ Hi Massimo, sorry your first experience as a challenge author was so negative. As you've noticed, the community has grown accustomed to certain freedoms regarding I/O, submission format, etc. It's one of the not-so-obvious facets of this site that unfortunately adds another hurdle to writing a challenge. We have a Sandbox for Proposed Challenges where folks can post their challenge ideas and get (usually more constructive) feedback before going live. I certainly hope you'll stick around and continue to write challenges! \$\endgroup\$ – Alex A. Apr 16 '16 at 21:36
  • 5
    \$\begingroup\$ If you have any questions about how the site works, I encourage you to ask on Meta or join us in chat and we'll try to help however we can. Thanks for being a member of the community and again I hope you'll stay. \$\endgroup\$ – Alex A. Apr 16 '16 at 21:38

13 Answers 13


Convex, 4 6 5 bytes

Crossed out 4 is still regular 4 :(

Note: As @Dennis pointed out, the input format I was using was not up to spec. This version should comply with the new rules, though.


Try it online


l       Read a line from input
 q      Read the rest of the input
  T     Push lowercase alphabet ("abcdefghijklmnopqrstuvwxyz")
   @    Rotate the top 3 items on the stack.
    er  Transliterate
        Implied output

Thanks to @LuisMendo for pointing out an error in the program

  • 1
    \$\begingroup\$ Nicely done, especially with your own language! Now let's wait for Dennis to beat this with Jelly. \$\endgroup\$ – Fund Monica's Lawsuit Apr 16 '16 at 0:12
  • 3
    \$\begingroup\$ Struck out 4 is still regular 4 ;( \$\endgroup\$ – user48538 Apr 16 '16 at 17:22
  • \$\begingroup\$ Added a link to codegolf.stackexchange.com/a/73584/48836 :P \$\endgroup\$ – cat Apr 19 '16 at 1:35

Pyth, 7 bytes


Try it online!

How it works:

        G = "abcdefghijklmnopqrstuvwxyz"
        z = input()
V.z     for N in all_input():
   XNGz     N.translate(G,z)    <--- automatically printed
  • \$\begingroup\$ It looks like with the new rules invalidate your submission, unfortunately. Quotes can't be included in the input like yours does. Don't worry, the new rules affected me too :P \$\endgroup\$ – GamrCorps Apr 16 '16 at 2:13
  • \$\begingroup\$ @GamrCorps Updated. \$\endgroup\$ – Leaky Nun Apr 16 '16 at 2:21

JavaScript ES6, 65 62 49 bytes

Saved 2 bytes thanks to Neil.


Takes an string of lines a and a dictionary i.

  • \$\begingroup\$ Use [...s] instead of s.split``. \$\endgroup\$ – Neil Apr 15 '16 at 23:34
  • \$\begingroup\$ @Neil Ah, yes, of course. \$\endgroup\$ – Conor O'Brien Apr 15 '16 at 23:35
  • \$\begingroup\$ On second thoughts, s.replace(/./g,x=>...) might be shorter still. \$\endgroup\$ – Neil Apr 15 '16 at 23:36
  • \$\begingroup\$ @Neil That would make it four bytes longer, no? \$\endgroup\$ – Conor O'Brien Apr 15 '16 at 23:37
  • \$\begingroup\$ @Neil Is that what you meant? \$\endgroup\$ – Conor O'Brien Apr 15 '16 at 23:39

sh + coreutils, 16 bytes

read s;tr a-z $s

15 bytes if input is from a terminal:

tr a-z `sed 1q`
  • \$\begingroup\$ That won't work. sed will close the stream. (At least it does on my machine.) \$\endgroup\$ – Dennis Apr 15 '16 at 23:37
  • \$\begingroup\$ @Dennis Ugh, it works when you type it in at the terminal... \$\endgroup\$ – Neil Apr 15 '16 at 23:39
  • \$\begingroup\$ Oh, I hadn't thought about that possibility... \$\endgroup\$ – Dennis Apr 15 '16 at 23:44

CJam, 12 8 bytes

4 bytes saved thanks to Dennis!


Try it online!


l        e# read a line
_$       e# fancy way to obtain string "abc...z". Thanks to Dennis!
q        e# read the rest of input as a string with newlines
\@       e# swap, rotate
er       e# transliterate. Implicit display
  • \$\begingroup\$ @Dennis That's very clever! \$\endgroup\$ – Luis Mendo Apr 15 '16 at 23:46

05AB1E, 5 bytes




[      # Start an infinite loop.
 A     # Push the lowercase alphabet.
  ¹    # Push the first input (substitution map).
   ‡   # Transliterate. Since the arity of this function is 3 and there are only 2 values
                        on the stack, it implicitly takes a line of input.
    ,  # Pop and print.

So this continually reads a line of input and prints a line of input after. Uses CP-1252 encoding. This is what I got with the console version:

D:\Golfing\05AB1E>C:\Python34\python.exe 05AB1E.py test.abe
greetings, planet!
ukttzoful, hsqftz!

Trying this online might be a bit weird, since 05AB1E is trying to read another line of input, but there is none, so you need to kill it to receive output (doesn't work all the time). It might be a better idea to do this with the console version of 05AB1E. Try it online!.


JavaScript 89


MATL, 14 bytes


The program exits with an error after producing the correct output (allowed by default).

Try it online

  • \$\begingroup\$ A single newline is not defined as EOI; if it's found in input, the program should simply not print anything and keep looping until input actually ends. \$\endgroup\$ – Massimo Apr 16 '16 at 0:31
  • \$\begingroup\$ @Massimo Corrected \$\endgroup\$ – Luis Mendo Apr 16 '16 at 0:42

Ruby, 35 31 29 bytes

Credit to @QPaysTaxes for the $_ trick, I had assumed that reading more from the STDIN object $< would change that variable, but it doesn't.


String#tr is basically a cipher substitution function, making things quite simple.

  • \$\begingroup\$ Because you only use c once, you can replace it with gets. Also, I'm not sure if it would work, but you could try replacing {|l| with ->l{. \$\endgroup\$ – Fund Monica's Lawsuit Apr 16 '16 at 0:23
  • \$\begingroup\$ You can't use it with gets because you're looping through an iterable with map and gets gets data from STDIN each time it's called. Bonus points because $< is the STDIN stream, making things potentially even more hectic. As for the arrow notation, it doesn't save bytes, and IIRC a lambda defined that way needs & in front of the procedure to make it work? \$\endgroup\$ – Value Ink Apr 16 '16 at 6:32
  • \$\begingroup\$ Oops, you're right. I wasn't paying attention to the function. What you can do is save a byte by just calling gets -- not assigning -- then using $_. As for the lambda notation, I'm not sure. I've almost never used it. \$\endgroup\$ – Fund Monica's Lawsuit Apr 16 '16 at 18:28
  • \$\begingroup\$ Thanks for the tip! I was able to find more tricks to further save bytes as well. \$\endgroup\$ – Value Ink Apr 16 '16 at 20:39

Pyth, 34 Bytes 31 Bytes 29 Bytes 27 Bytes

Saved 3 5 7 bytes thanks to Kenny Lau


Try it out!

  • \$\begingroup\$ You can use V instead of Fd (but you'll have to change the variable names afterwards) :) \$\endgroup\$ – Leaky Nun Apr 15 '16 at 23:29
  • \$\begingroup\$ You can also save 2 bytes by changing ?XpYpZ to p?XYZ. \$\endgroup\$ – Leaky Nun Apr 15 '16 at 23:32
  • \$\begingroup\$ An array of strings is not the proper input format. \$\endgroup\$ – Massimo Apr 16 '16 at 1:54

Python 3, 50 bytes

lambda s,k:s.translate(dict(zip(range(97,122),k)))

Or if we really have to implement an infinite loop:

Python 3, 70 bytes

while 1:print(input().translate(t))
  • \$\begingroup\$ I think you have to take a list of strings instead of one string as input. \$\endgroup\$ – Conor O'Brien Apr 15 '16 at 23:33

Factor, 155 bytes

The logic is actually pretty simple, it's just constraining to the REPL requirement that costs.

[let "abcdefghijklmnopqrstuvwxyz" readln string>array bi@ zip :> T [ t ] [ T readln string>array [ dup T key? [ T at ] [ ] if ] map "" join print ] while ]

Readable single-function version (don't ever write code like this):

:: monolithic-repl ( -- )
    "abcdefghijklmnopqrstuvwxyz" readln string>array bi@ zip 
  :> table
  [ t ] 
  [ table readln string>array
    [ dup table key? 
      [ table at ] [ ] if 
    ] map
    "" join print 
  ] while ;

Readable, Factored version:

:: cipher-print ( cipher-table -- )
  readln string>array
  [ dup cipher-table key? [ cipher-table at ] [ ] if ] map
  "" join print ;

: cipher-get ( -- cipher )
  "abcdefghijklmnopqrstuvwxyz" readln
  string>array bi@ zip ;

:: cipher-repl ( -- )
  cipher-get :> table
  [ t ] [ table cipher-print ] while ;

C++, 154 Bytes

#include <iostream.h>
#include "string.h"
using namespace std;

void encript_string() {
char en[26],in[1024];
string s=cin.getline();
 int i=0,m=0;
 while(in[i] != 10) {
  • 1
    \$\begingroup\$ This is a snippet, which is not allowed by our rules. Submissions must be functions or full programs. \$\endgroup\$ – user45941 Apr 22 '16 at 7:54
  • \$\begingroup\$ Why it displays in same line ?? (Removes new line character ?) \$\endgroup\$ – parth patel Apr 22 '16 at 9:31
  • \$\begingroup\$ This answer isn't valid because you're missing necessary header includes like iostream and string. \$\endgroup\$ – user45941 Apr 22 '16 at 19:53
  • \$\begingroup\$ I seem to be getting errors from this \$\endgroup\$ – MilkyWay90 Mar 23 '19 at 17:47

Not the answer you're looking for? Browse other questions tagged or ask your own question.