Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I wrote some text, but it looks too professional. I want to make it look like I was really tired when I wrote it. I need you to insert some typos.

Your challenge is to take an arbitrary single line of text, and add typos. This means that for each character, there will be a 10% chance for it to be typofied.

The definition of "typofied" is that you must choose (randomly) one of the following:

  • Duplicate the character.
  • Delete the character.
  • Shift the character one keyboard space. The "keyboard" is defined as:


    For the character shift, you must go one space up, down, left, or right. This must be chosen randomly. The shift option only applies to alphabetic characters. Case must be preserved. Be careful with edge-cases, like m!

The definition of "random" is that the result must not be predictable (by looking at previous results). For example, you can't typofy every tenth character. Furthermore, the randomness must have an even distribution. For example, you can't do 30% duplicate, 30% delete, and 40% shift; it has to be a 1/3 chance for each (1/2 for each if it's a nonalphabetic character).

Example input:

This is some correct text. It is too correct. Please un-correctify it.

Example output:

This iissome xorreect tex..  It is too coteect. Please jn-corretify it.

This is , so the shortest code in bytes will win.

share|improve this question
What about accidentally striking the capslock key? When one types an "A" or "Z", there should be a random chance that they will hit capslock instead, ND END UP LIKE THIS. – AJMansfield Feb 10 '14 at 1:10
@AJMansfield Lol, that would probably be too complicated. It's already complicated enough as it is :P – Doorknob Feb 10 '14 at 1:12
@user2509848 Hey, stop ,aking it ,ore co,plicated than it already is! :-P – Doorknob Feb 10 '14 at 3:40
@Doorknob Your example output doesn't look like you were tired, it looks like you're new to typing and you don't know how to correct typos. (Or you didn't look over what you'd typed at all.) – Blacklight Shining Feb 10 '14 at 4:42
"edge-cases" <-- I see what you did there. *slow clap* – Adam Maras Feb 12 '14 at 23:52

12 Answers 12

up vote 15 down vote accepted

GolfScript, 120 characters

{10{rand}:R~!{[{.}{;}{Z\?[.(.10-@).10+]{Z=}%' '-.,R=}]'QWERTYUIOP ASDFGHJKL  ZXCVBNM'' '22*11/*.{32|}%+:Z 2$?0>2+R=~}*}%

The code can be tested here.

{                      # loop over all characters
  10{rand}:R~!         # take random number [0..9] and negate (i.e. 10% chance of true)
  {                    # {...}* is the if-block
    [                  # Three possible operations (code blocks) in the arry
      {.}              # a) duplicate
      {;}              # b) delete
      {                # c) shift
        Z              #      Z is the keyboard layout (see below)
        \?             #      Find the index of the current letter
        [.(.10-@).10+] #      Calculate index of letter left, right, above, below
        {Z=}%          #      Extract the corresponding letters for indices
        ' '-           #      Remove any spaces
        .,R=           #      Take random item
                       # Z is the keyboard layout (upper and lower case)
                       # with enough spaces around
    'QWERTYUIOP ASDFGHJKL  ZXCVBNM'' '22*11/*.{32|}%+:Z
    2$?0>              # Is the current letter contained in Z and not a space?
    2+                 # Add 2 (i.e. 3 for letters, 2 for any other char)
    R=                 # Take a random code block from above
    ~                  # Execute the block
share|improve this answer

C, 358 bytes

(There are only three lines of code, but I've broken up line 3 for legibility)

#define x putchar
#define y random()
x(s[n][y%strlen(s[n])]|(c&32));continue;}if (y&1)x(x(c));}}

The array of strings at the beginning lists the possible adjacent keys for each letter of the alphabet. I had to double up the "O" (adjacent to "P") to avoid calculating random()%1 when selecting a shifted character.

Test run:

$ echo "This is some correct text. It is too correct. Please un-correctify it." |./a.out
This is some  cofrect teext. It is too correct.. Plleaase un-correctify it..


Here's an expanded and commented version of the same source code:

#include <stdio.h>
#include <string.h>
/* ^^ These should be included, but the code compiles without them */

int c,n;

void main() {

  /* Adjacent keys for each letter of the alphabet (A, B, C, ..., Z): */
  char *s[26] = { "QS","HNV","FVX","EFSX","DRW","CDGR","FHTV","BGJY","KOU","HKNU",
                  "BCG","ESQ","CDZ","HTU","SX" };

  /* Fetch input until null character or EOF reached */
  while ((c=getchar())>0) {

    /* For 90% of the time, just echo the character unchanged */
    if (random()%10>0 && putchar(c)) continue;

    /* If it's a letter of the alphabet, shift with 33% probability */
    if (isalpha(c) && random()%3<1) {
      /* Calculate offset to adjacent keys data */
      /* Choose a random adjacent key, and change to lower case if needed */

    /* If we reach this point, either we didn't fetch an alphabet character, or   */
    /* we did but chose not to shift it. Either way, we now need to either repeat */
    /* the character or delete it, with 50% probability for each. */

    /* This repeats the character by printing the return value from putchar() */
    if (random()&1) putchar(putchar(c));

    /* To delete the character, we don't have to do anything. */
share|improve this answer
I fairly certain you don't need to put the 26 in char*s[26]. The compiler should be able to figure that out itself. – FDinoff Feb 10 '14 at 3:32
+1 because I stole your bit-level ascii magic. – Kaya Feb 10 '14 at 5:38
@FDinoff Ah, of course. Not much point editing now; the ship's already sunk :-D – squeamish ossifrage Feb 10 '14 at 9:11
you could also replace both continues with elses. (leave the ; where the first one was). – AShelly Feb 10 '14 at 15:48
What's the problem with random()%1? Any int % 1 should be 0. – immibis Feb 12 '14 at 3:41

Ruby, 168

Slightly shorter take using an array indexing strategy:


Original regular expression version (184):

gets.chars{|c|c=~/\w/&&(s[c]?s: s.upcase)=~/((\w).{9})?((\w)|.)#{c}((\w)|.)(.{9}(\w))?/
share|improve this answer
Sorry, I can't read Ruby. Here I ran this program 10 times with STDIN '0123456789'x10 i.e. 100 digits (i.e. 1000 digits total in 10 runs), and there was never duplicated digit in the output. Is there a problem with that site, or my understanding of how it all works? – Vadim Feb 10 '14 at 18:21
@VadimR good catch, thanks! I had started using Kernel#putc to print out the output since that didn't require parens, saving me one character. Of course putc only prints the first character, and the output string can sometimes be two characters long. Stupid mistake. Try this version! – Chron Feb 10 '14 at 21:41
Perfect now. Thank you. – Vadim Feb 10 '14 at 23:02

Python, 251

from random import*
print"".join(w([z]*9+[w(["",z*2]+[chr(o(w("DGRC FHTV GJYB UOK HKUN JLIM KO NK BMJ IPL O WA ETF ADWZ RYG YIJ CBG QES ZCD TUH XS SQ VNH XVF SFEX WRD".split()[(o(z)&31)-6]))|o(z)&32)]*z.isalpha())])for z in raw_input())

Very simple look-up technique, for a moment I thought it might be cheaper to encode the keyboard as a undirected graph but the overhead for creating such a type in Python proved prohibitive. Since Python's random functions have too-descriptive names I use choice() exclusively, renaming it to w. The 10% chance of error is handled by w([z]*9+[...]) where the nine copies of an un-typoed character are in a list with one typo.

-16 characters--thanks grc, +2 characters (and correctness, worth many more than 2 chars)--thanks Dhara

share|improve this answer
Some minor improvements: use spaces as the delimiter d="SQ VNH XVF...".split(), remove the space after print, and replace the if/else with ([...]+[...])*z.isalpha(). Also, you don't need a variable for d since you only use it once. – grc Feb 10 '14 at 2:03
You can do w=__import__('random').choice (at least in Python 3 afaik). – SimonT Feb 10 '14 at 3:55
This code breaks with several text-characters: ?;:< etc – Dhara Feb 10 '14 at 12:23
Also, it has an off-by-one error in indexing: 'b' in 'bbbbbbbb' are replaced by 'x', 'zzzzzzzzzz' gives an index out of bounds – Dhara Feb 10 '14 at 12:29
Use Python 3's input() and print() to save 2 chars. – Cees Timmerman Feb 11 '14 at 14:07

JS, 303, 288, 275, 273, 274 (bug fix)

function z(s){return s.split('').map(function(d){if((r=Math.random)(b='qwertyuiop0asdfghjkl000zxcvbnm')>.1)return d
if((c=r(x=(d>'`'?b:(b=b.toUpperCase())).indexOf(d))*(/[a-z]/i.test(d)+2))<2)return c>1?d+d:''
return a}).join('')}

Algorithm for the keyslip:

  • find char in string (or uppercase)
  • add 11, -11, 1 or -1 to the index.
  • if it's invalid (0 or null), re-roll

Non-Golfed version per request:

function z (s) {
  return s.split('') // split input string into characters.
          .map( // and then for each character...
    function (d) {
      r = Math.random; // set up a shortened form of Math.random
      // declare keyboard here because we have parens and we can save a delimeter.
      b = 'qwertyuiop0asdfghjkl000zxcvbnm';  
      if (r() > .1) {  // normal case
        return d;
      numOptions = /[a-z]/i.test(d) + 2; // if it's a character, 1+2, else 0+2 options

      // test here because we have parens. x might be -1
      if (d > '`') { 
        x =;  // x marks the spot
      } else {
        b = b.toUpperCase();
        x =;

      c = r() * numOptions; // chars can be 0-3, non-chars: 0-2
      if (c < 2) {                // this case is simple, so it comes first
        return c>1 ? d + d : ''; // double or omit.

      // we must be in keyslip mode.

      // in the golfed code, this while loop become for loops, 
      // but it's really a while.
      a = 0;
      while (!a) { // that is, a != null && a != 0
        v = ~~(r() * 4); // 0, 1, 2, or 3
        newX = x + [11, -11, 1, -1][v]; // choose one
        a = b[newX];  // slip the key
      return a;
  ) // end the map function
  .join('') // and then reassemble the string
share|improve this answer
Bravo! JS ninja awarded! – Sunny R Gupta Feb 10 '14 at 10:13
@SunnyRGupta Thanks! Wish I could get it down more. I think the massive parentheses hell might make it longer than needed. – Not that Charles Feb 10 '14 at 16:41
Also try to display the non-minified version for novices! – Sunny R Gupta Feb 11 '14 at 7:35
Well, technically your code has 277 bytes on windows. You SHOULD replace all newlines with ;. That is the only way to say that it actually has 274 bytes. Besides, it only works on newer Javascript and JScript versions. – Ismael Miguel Feb 13 '14 at 12:42

C#, 320 bytes (360 bytes with program wrapping)

Includes support for "shifted" upper-case letters.

As a function (320 bytes):

string T(string s){
    string t="",z="      ",k=z+z+"qwertyuiop asdfghjkl   zxcvbnm";
    var r=new System.Random();
    foreach(var c in s){
            int i=r.Next(k.IndexOf(c)>0?3:2);
                while(' '==k[i=k.IndexOf(c)+m[r.Next(4)]]);
            else if(i>0)
    return t;

As a program that reads a line of text (360 bytes):

using System;
class P{
    static void Main(){
        string t="",z="      ",k=z+z+"qwertyuiop asdfghjkl   zxcvbnm";
        var r=new Random();
        foreach(var c in Console.ReadLine()){
                int i=r.Next(k.IndexOf(c)>0?3:2);
                    while(' '==k[i=k.IndexOf(c)+m[r.Next(4)]]);
                else if(i>0)

Input output sample:

This is some correct text. It is too correct. Please un-correctify it.
This  is some corrrect texy. Ut is too correct. Pease un-coorrectify it.

share|improve this answer
Legal C# programs need to have at the least "public class A{static void Main(){}}" to be valid. You will then need to read in from console. But it looks like your solution will still be shorter than mine, so well done. – Xantix Feb 10 '14 at 0:23
@Xantix, I know, but they never said it had to be a program. Either way, my answer now includes program wrappings. – Hand-E-Food Feb 10 '14 at 0:45
I just realised, my function will accept CR and LF characters in the input which could potentially be doubled or dropped. That would make for interesting output... – Hand-E-Food Feb 10 '14 at 0:46
Hmm, not enough random calls to make Func<int,int> n=x=>r.Next(x); a good idea. If only the compiler could infer the type for delegates... – Magus Feb 11 '14 at 0:13

Perl, 278 239 197 169 162 156 151 149

s#((\pL)|.)#rand>.1?$&:($&x2,'',do{1until/^.{@{[(2,-10,12)[rand 4]-1+index$_=QWERTYUIOP0ASDFGHJKL000ZXCVBNM,uc($,=$&)]}}(\D)/;$,&' '|$1})[rand@-]#ge

Run with -p, then 148+1=149 bytes. E.g.:

perl -p
Your challenge is to take an arbitrary single line of text, and add typos.
You challenge is to tale an  arbitrary singe lind of text, and add yposs.
This is some correct text. It is too correct. Please un-correctify it.
This iis some correct text. It s too coorrect.Pleqse un-correctify it.

Un-golfed, more or less:

    ? $&
    : ($&x2,'',
            1until/^.{@{[(2,-10,12)[rand 4]-1
            $,&' '|$1

At first I thought that choosing element randomly in an array (of 26 of them of different lengths) is more statistically 'clean' (i.e. random), but maybe it was wrong. (See previous version.) This last attempt is, following the leaders:-), stepping along a string by either -1,1,-11,11 (randomly) and repeating until valid step.

Edit: Thanks to tobyink help and other optimizations, we managed to considerably reduce code size.

The last approach uses some tricks with regexp search to find valid step along substitution string, eliminating manual checks.

Another edit: 5 bytes off because we don't need integers for array indexes + small trick with illegal array index. I tried same trick with [-4+rand@-] (i.e. negative indexes) and get rid of one list element, '', but it didn't save anything.

Edit: Back to simplicity - replacing condition ~~rand 10 with rand>.1 saves 2 bytes...

share|improve this answer
There's no need for a semicolon after the definition of sub i. You're not using strict, so 'QWERTYUIOP0ASDFGHJKL000ZXCVBNM' can be given as a bareword (saves two quote mark characters). Similarly, so can 'Z' (though this means you need to add a space between it and gt, so it only saves one character). Total savings: 4 characters. – tobyink Feb 11 '14 at 10:43
The construct ($n=i$&=~/\pL/?3:2)?--$n?do{...}:$&x2:'' can be rewritten as ($&x2,'',do{...})[i$&=~/\pL/?3:2]. It means that the evaluation isn't lazy (it calculates all three ways that the character could be substituted before deciding on a substitution technique), but it works, and it saves another seven characters by my calculations. – tobyink Feb 11 '14 at 11:01
Oh, I just noticed you have whitespace before gt'Z' too - that can be dropped. With all these changes, you should be able to get it down to 184 characters. – tobyink Feb 11 '14 at 11:05
@tobyink, many thanks, especially for your second comment - how I didn't see this construct there, I don't know :-(. Sub is gone (saves us a couple of bytes). Barewords trick is nice, too, and actually I was already doing it when I read your comment. :-) Thanks again. – Vadim Feb 12 '14 at 0:16
I've got one more character for you. If you rename $s to $, (this built-in variable is the field separator for print, but you're not printing multiple fields anywhere, so it's built-in usage is irrelevant, making the variable ripe for reuse), then you can eliminate the white space in $s x3 making it just $,x3. – tobyink Feb 12 '14 at 0:49

PHP, function with 368 bytes

Here is my attempt.

It's some "frankencode", but it kinda works.

function _($m){$q=array(array('qwertyuiop','asdfghjkl',' zxcvbnm'),'!.-,;?+/');$r='mt_rand';foreach(str_split($m)as$k=>$c)if(!$r(0,9)&&$c!=' ')foreach($q[0]as$x=>$y)if(($z=strpos($y,$c))!==!1){switch($t=$r(-3,2-($z>>3)-($x>>1))){case 2:++$z;break;case 1:++$x;break;case -1:--$x;break;case -2:--$z;break;case -3:$z=8;break;}$m[$k]=$t?$q[0][$x][$z]:$q[1][$z];}return$m;}

A more "readable" code:

function _($m)
    $q=array(array('qwertyuiop','asdfghjkl',' zxcvbnm'),'!.-,;?+/');
        if(!$r(0,9)&&$c!=' ')
                        case 2:
                        case 1:
                        case -1:
                        case -2:
                        case -3:

The only difference between the 2 codes is that one has tons of tabs and newlines.

It doesn't produce the same exact type of "incorrectness", but it either deletes or replaces a char using the said conditions.

You can try it at

Copy and paste this code:

function _($m){$q=array(array('qwertyuiop','asdfghjkl',' zxcvbnm'),'!.-,;?+/');$r='mt_rand';foreach(str_split($m)as$k=>$c)if(!$r(0,9)&&$c!=' ')foreach($q[0]as$x=>$y)if(($z=strpos($y,$c))!==!1){switch($t=$r(-3,2-($z>>3)-($x>>1))){case 2:++$z;break;case 1:++$x;break;case -1:--$x;break;case -2:--$z;break;case -3:$z=8;break;}$m[$k]=$t?$q[0][$x][$z]:$q[1][$z];}return$m;}
echo _('This is some correct text. It is too correct. Please un-correctify it.');

After testing, please, tell me if it is a valid answer.

share|improve this answer
It doesn't seem to affect capital letters at all. – squeamish ossifrage Feb 9 '14 at 22:26
The capital letters are unaffected in the example. But yes, it doesn't. But also notice that I said that it KINDA works. – Ismael Miguel Feb 9 '14 at 23:32

C#, 581 bytes

using System;class B{static void Main(){var z=Console.ReadLine();var r=new Random();foreach(char C in z){String o;if(r.Next(10)==0){int w=r.Next(3);o=w==0?C+""+C:w==1?"":f(C,r);}else{o=C+"";}Console.Write(o);}Console.ReadLine();}static string f(char C,Random r){string[]k={"00000000000","0qwertyuiop0","0asdfghjkl0","00zxcvbnm0","000000000"};char L=char.ToLower(C);char h='0';for(int i=1;i<4;i++){var d=k[i].IndexOf(L);if(d!=-1){while(h=='0'){int n=r.Next(4);h=n==0?k[i][d-1]:n==1?k[i][d+1]:n==2?k[i-1][d]:k[i+1][d];}h=char.IsUpper(C)?char.ToUpper(h):h;return h+"";}}return C+"";}}

and in a more readable format:

using System;

class A
    static void Main()
        var z = Console.ReadLine();
        var r = new Random();

        foreach (char C in z)
            String o;

            if (r.Next(10) == 0)
                int w = r.Next(3);
                o = w == 0 ? C + "" + C :
                    w == 1 ? "" :
                             f(C, r);
                o = C + "";


    static string f(char C, Random r)
        string[] k = {
        char L = char.ToLower(C);
        char h = '0';

        for (int i = 1; i < 4; i++)
            var d = k[i].IndexOf(L);

            if (d != -1)
                while (h == '0')
                    int n = r.Next(4);

                    h = n == 0 ? k[i][d - 1] :
                        n == 1 ? k[i][d + 1] :
                        n == 2 ? k[i - 1][d] :
                                 k[i + 1][d];
                h = char.IsUpper(C) ? char.ToUpper(h) : h;
                return h + "";
        return C + "";
share|improve this answer

PHP, 326 320 318 315 chars


And a more readable and commented version:

// $a   input
// $b   char iterator
// $c   current char ascii value
// $d   current char
// $e   is uppercase
// $g   rand() output
// $h   char displacement
// $i   current character in $h
// $j   temporary var for uppercasing

// the neighbouring characters of a-z, in alphabetical (and ASCII) order
// input from argument

    echo!rand(0,9)&&($c=ord($d)-65)? /* 10% chance, read char ASCII value - 65 into $c */
          /* random number from 0 to 2 (if alphabetic) or 0 to 1 stored in $g */
            $d.$d: /* double char if $g = 0 */
                "": /* omit char if $g = 1*/
                  /* $j = random neighbour of the current char */
                    strtoupper($j): /* uppercase $j */
        :$d; /* keep char */

Still could be improved, I suppose.

-2, -3 thanks to Ismael Miguel

share|improve this answer
Where you have (!($g=rand(0,($e=($c>-1&&$c<26)or$c>31&&$c<58)?2:1)) change for (!($g=rand(0,($e=($c>-1&&$c<26)or$c>31&&$c<58)+1))? and you will save 2 bytes. – Ismael Miguel Feb 11 '14 at 9:24
Where you have ($e?0:32), replacing with 32*!!$e (notice the lack of parenthesis) save 2 bytes. If $e is ALWAYS boolean, you can do 32*!$e and you save 3 bytes. This will work cause php has arithmetic precedence. This means that multiplications and divisions are made before any addition and subtraction. – Ismael Miguel Feb 13 '14 at 20:15

Java (475 bytes)

This is my try in the verbose language that is Java. Getting random numbers is quite long in Java, and the mapping isn't really efficient. It can probably be improved.

import static java.lang.Math.*;public class T{public static void main(String[]a){String z="",v;for(char c:a[0].toCharArray()){double g=random()*60;if(g>=6)z+=c;else{boolean u='A'<=c&c<='Z',l='a'<=c&c<='z';if(g<(l|u?2:3))z+=""+c+c;else if((l|u)&g<4){v="qs,hnv,fvx,efsx,drw,cdgr,fhtv,kou,bgjy,hknu,ijlm,ko,kn,bjm,ilp,o,aw,eft,adwz,gry,ijy,bcg,eqs,cdz,htu,sx".split(",")[u?c-'A':c-'a'];c=v.charAt((int)(random()*v.length()));z+=u?(char)(c-'a'+'A'):c;}}}System.out.println(z);}}


java T "This is some correct text. It is too correct. Please un-correctify it."

Uncompressed, accolades added:

import static java.lang.Math.*; // Need random()

public class T {
    public static void main(String[] a) {
        String z = "", v;
        for (char c : a[0].toCharArray()) {
            double g = random() * 60; // Compute random only once for two cases.
            if (g >= 6) {
                // 90% must be correct (accolades are stripped)
                // so we just copy the character.
                z += c;
            } else {
                // These tests come often.
                boolean u = 'A' <= c & c <= 'Z', l = 'a' <= c & c <= 'z';

                // reuse the random. g is [0,6[.
                if (g < (l | u ? 2 : 3)) { 
                    // If c is an ascii letter (l|u) then g must be [0,2[ ; if not, then g must be [0,3[.
                    // If those conditions are met, we duplicate the character
                    z += "" + c + c;
                } else if ((l | u) & g < 4) {
                    // if c is letter and g [2,4[ then we perform the wrong key event.
                    // I could not compress it using the keyboard mapping shorter in Java than expanding it like it is now.
                    v = "qs,hnv,fvx,efsx,drw,cdgr,fhtv,kou,bgjy,hknu,ijlm,ko,kn,bjm,ilp,o,aw,eft,adwz,gry,ijy,bcg,eqs,cdz,htu,sx".split(",")[u ? c - 'A' : c - 'a'];
                    // get a random character from the string.
                    c = v.charAt((int) (random() * v.length()));

                    // Keep the case of the character.
                    z += u ? (char) (c - 'a' + 'A') : c;
                } else { // if c is not an ascii letter or if g is [4,6[
                    // Do nothing. This else is stripped.
share|improve this answer

AutoHotkey 441 bytes

The input must be given as a command line parameter, the output is given as an error message.

Golfed version

loop, parse, 1
if r(10)!=10{
for x,y in k
if q=1
h.=a a
if q=3
} until k.HasKey(w)
throw % h
return w

Un-golfed and annotated version (difference is that this version has more white space and the variable assignments are on separate lines for readability.)

loop, parse, 1
    ;get a random number from 1-10 and check if it is 10
    ;  if it isn't skip the rest of this iteration
    if r(10)!=10

    ;check if the current character is in the k
    for x,y in k

    ;choose a random number to decide what typo to do
    if q=1
        h.=a a ;duplicate the key
    if q=3
        ;the keyboard array is set up so that by adding or subtracting
        ;  20 from the index you are moving up or down a row
        ;  and by adding or subtracting 1 you move right or left
        ;  then you just need to check if the adjusted index
        ;  is valid
        } until if k.HasKey(w)
;display the string as an error message
throw % h
    return w
share|improve this answer
With which programs does this work? – Ismael Miguel Feb 13 '14 at 12:38
It is run by AutoHotkey.exe. – Person93 Feb 13 '14 at 16:24

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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