Tell me more ×
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.

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:

    qwertyuiop
    asdfghjkl
     zxcvbnm
    

    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
 
So if M is shifted, it has a 50% chance to be N and a 50% chance to be K? –  Chron 11 hours ago
 
@Chron Correct. –  Doorknob 11 hours ago
 
From your example input/output I assume that Space counts as a character that can be duplicated and deleted, but not shifted. Also are capitals to be preserved? –  Xantix 10 hours ago
1  
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 8 hours ago
2  
@AJMansfield Lol, that would probably be too complicated. It's already complicated enough as it is :P –  Doorknob 8 hours ago
show 7 more comments

10 Answers

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()
c,n;main(){char*s[26]={"QS","HNV","FVX","EFSX","DRW","CDGR","FHTV","BGJY","KOU","HKNU",
"IJLM","KO","KN","BJM","ILP","OO","AW","EFT","ADWZ","GRY","IJY","BCG","ESQ","CDZ","HTU",
"SX"};while((c=getchar())>0){if(y%10>0&&x(c))continue;if(isalpha(c)&&y%3<1){n=(c&31)-1;
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..

Update:

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",
                  "IJLM","KO","KN","BJM","ILP","OO","AW","EFT","ADWZ","GRY","IJY",
                  "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 */
      n=(c&31)-1;
      /* Choose a random adjacent key, and change to lower case if needed */
      putchar(s[n][random()%strlen(s[n])]|(c&32));
      continue;
    }

    /* 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 6 hours ago
 
+1 because I stole your bit-level ascii magic. –  Kaya 4 hours ago
 
@FDinoff Ah, of course. Not much point editing now; the ship's already sunk :-D –  squeamish ossifrage 34 mins ago
add comment

Ruby, 183

s='.qwertyuiop.asdfghjkl...zxcvbnm.'
gets.chars{|c|c=~/\w/&&(s[c]?s: s.upcase)=~/((\w).{9})?((\w)|.)#{c}((\w)|.)(.{9}(\w))?/
putc rand<0.9?c:[c*2,'',*[*$2,*$4,*$6,*$8].sample].sample}
share|improve this answer
add comment

Python, 249

from random import*
w=choice
o=ord
print"".join(w([z]*9+[w(["",z*2]+[chr(o(w("SQ VNH XVF SFEX WRD DGRC FHTV GJYB UOK HKUN JLIM KO NK BMJ IPL O WA ETF ADWZ RYG YIJ CBG QES ZCD TUH XS".split()[o(z)&31-1]))|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.

share|improve this answer
2  
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 7 hours ago
1  
You can do w=__import__('random').choice (at least in Python 3 afaik). –  SimonT 5 hours ago
 
@SimonT ahh, but unfortunately len("w=__import__('random').choice")=29 while len("from random import*;w=choice")=28. –  Kaya 4 hours ago
add comment

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";
    k+=k.ToUpper()+z+z;
    int[]m={-11,-1,1,11};
    var r=new System.Random();
    foreach(var c in s){
        if(r.Next(10)>0)
            t+=c;
        else{
            int i=r.Next(k.IndexOf(c)>0?3:2);
            if(i>1){
                while(' '==k[i=k.IndexOf(c)+m[r.Next(4)]]);
                t+=k[i];
            }
            else if(i>0)
                t=(t+c)+c;
        }
    }
    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";
        k+=k.ToUpper()+z+z;
        int[]m={-11,-1,1,11};
        var r=new Random();
        foreach(var c in Console.ReadLine()){
            if(r.Next(10)>0)
                t+=c;
            else{
                int i=r.Next(k.IndexOf(c)>0?3:2);
                if(i>1){
                    while(' '==k[i=k.IndexOf(c)+m[r.Next(4)]]);
                    t+=k[i];
                }
                else if(i>0)
                    t=(t+c)+c;
            }
        }
        Console.Write(t);
    }
}

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.

TYPO RAGE CAPS TEXT!
TYPPORAGE CAOS TEX!
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 9 hours ago
 
@Xantix, I know, but they never said it had to be a program. Either way, my answer now includes program wrappings. –  Hand-E-Food 9 hours ago
 
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 9 hours ago
add comment

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'),'!.-,;?+/');
    $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;
}

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 http://writecodeonline.com/php/.

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 11 hours ago
 
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 10 hours ago
add comment

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);
            }
            else
            {
                o = C + "";
            }

            Console.Write(o);
        }
    }

    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 + "";
    }
}
share|improve this answer
add comment

Perl, 278 239

sub i{int rand$_[0]};s#.#i(10)?$&:($n=i$&=~/\pL/?3:2)?$n-1?($_=substr+($_=qw/SQ VNH XVF SFEX WRD DGRC FHTV GJYB UOK HKUN JLIM KO NK BMJ IPL O WA ETF ADWZ RYG YIJ CBG QES ZCD TUH XS/[ord(uc$&)-65]),i(length),1)&&($& gt'Z')?lc:$_:$&x2:''#ge

Run with -p, then 238+1=239 bytes. E.g.:

perl -p typos.pl
This is some correct text. It is too correct. Please un-correctify it.
This is  some correct trxt. It is too correct. Pleaseun-correctify it.
I wrote some text, but it looks too professional.
I wrote some ret, htit looks too professiilnal.
I want to make it look like I was really tired when I wrote it.
I want  to mqke it look like I was reaally tired when I wroteit.
I need you to insert some typos.
I eed youu t inseert sooke typos.

Un-golfed, more or less:

sub i{int rand$_[0]};
s#.#
i(10)
    ?$&
    :($n=i$&=~/\pL/?3:2)
        ?$n-1
            ?
                (
                    $_=substr +($_=qw/SQ VNH XVF SFEX WRD DGRC FHTV GJYB UOK 
                        HKUN JLIM KO NK BMJ IPL O WA ETF ADWZ RYG 
                        YIJ CBG QES ZCD TUH XS/[ord(uc$&)-65])
                    ,i(length),1
                )
                &&
                ($& gt'Z')
                    ?lc
                    :$_
            :$&x2
        :''
#ge;
share|improve this answer
add comment

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
add comment

PHP, 326 chars

$h=array(qs,vhn,vxf,sefx,wrd,drgc,fthv,gyjb,uko,hukn,jilm,ok,nk,bjm,ilp,o,aw,etf,awdz,rgy,yji,cgb,qse,zdc,thu,sx);$a=$argv[1];for(;$d=$a[++$b];)echo!rand(0,9)&&($c=ord($d)-65)?(($e=($c>-1&&$c<26))||($c>31&&$c<58)?(($g=rand(0,2))==0?$d.$d:($g==1?"":$h[$c-($e?0:32)][rand(0,strlen($h[$c-($e?0:32)]))])):(rand(0,1)?$d.$d:"")):$d;

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

// the neighbouring characters of a-z, in alphabetical (and ASCII) order
$h=array(qs,vhn,vxf,sefx,wrd,
    drgc,fthv,gyjb,uko,hukn,
    jilm,ok,nk,bjm,ilp,
    o,aw,etf,awdz,rgy,
    yji,cgb,qse,zdc,thu,
    sx);
$a=$argv[1]; // input from argument

for(;$d=$a[++$b];)
    echo!rand(0,9)&&($c=ord($d)-65)? /* 10% chance, read char ASCII value - 65 into $c */
        (($e=($c>-1&&$c<26))||($c>31&&$c<58)? /* is alphabetical? + is uppercase in $e */
            (($g=rand(0,2))==0? /* $g = 0 to 2, = 1/3 chance */
                $d.$d: /* double char */
                ($g==1?
                    "": /* omit char */
                    $h[$c-($e?0:32)][rand(0,strlen($h[$c-($e?0:32)]))])
                        /* a random character from the character's neighbours */
            ):
            (rand(0,1)?
                 $d.$d: /* double char */
                 "")): /* omit char */
        $d;

Still could be improved, I suppose.

share|improve this answer
add comment

JS, 303

function z(s){return s.split('').map(function(d){if((r=Math.random)()>.1)return d
if((c=r()*(/[a-z]/i.test(d)?3:2))<2)return c>1?d+d:''
if((x=(b="qwertyuiop0asdfghjkl000zxcvbnm").indexOf(d))<0)x=(b=b.toUpperCase()).indexOf(d)
for(a=0,n=11;i=!a;a=b[x+n])for(v=r()*4;v>i;n=i++%2?-n:1);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
share|improve this answer
add comment

Your Answer

 
discard

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.