Insert typos into text


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. */

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))?/

GolfScript, 120 characters

{10{rand}:R~!{[{.}{;}{Z\?[.([email protected]).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
        [.([email protected]).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