Insert typos into text

65

18

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.

Doorknob

Posted 2014-02-09T19:51:09.033

Reputation: 68 138

So if M is shifted, it has a 50% chance to be N and a 50% chance to be K? – Paul Prestidge – 2014-02-09T22:32:14.520

@Chron Correct. – Doorknob – 2014-02-09T22:44:09.003

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 – 2014-02-09T23:03:15.443

@Xantix Yes to both. – Doorknob – 2014-02-09T23:05:31.027

Wish I remembered more TECO; being a terse language specifically for editing, I suspect it could be a winner here. – keshlam – 2014-02-09T23:56:04.523

4What 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 – 2014-02-10T01:10:32.433

3@AJMansfield Lol, that would probably be too complicated. It's already complicated enough as it is :P – Doorknob – 2014-02-10T01:12:13.013

I have accidentally typed ',' instead of 'm' before. – None – 2014-02-10T03:20:50.790

1@user2509848 Hey, stop ,aking it ,ore co,plicated than it already is! :-P – Doorknob – 2014-02-10T03:40:35.020

OK, I guess we would then have to add numbers and other keyboard characters. – None – 2014-02-10T03:43:58.000

1@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 – 2014-02-10T04:42:32.157

@Blacklight Heh, that works too. :-P – Doorknob – 2014-02-10T12:47:47.953

@Sumurai Oooh, maybe that could be adapted for this challenge and used here! – Doorknob – 2014-02-10T12:48:45.323

Can strings be arbitrarily large after execution? I mean, if I duplicate a character, when I move on, am I going to reroll on that duplicate and maybe duplicate again, or go through to the next one. That is, is the size of the output string bounded by 2n? – Cruncher – 2014-02-10T16:10:44.627

@Cruncher No; after duplicating a character you do not reconsider the duplicated character. – Doorknob – 2014-02-10T19:13:59.203

1"edge-cases" <-- I see what you did there. *slow clap* – Adam Maras – 2014-02-12T23:52:58.013

Answers

15

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
  }*
}%

Howard

Posted 2014-02-09T19:51:09.033

Reputation: 23 109

19

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

r3mainer

Posted 2014-02-09T19:51:09.033

Reputation: 19 135

2I 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 – 2014-02-10T03:32:18.303

@FDinoff Ah, of course. Not much point editing now; the ship's already sunk :-D – r3mainer – 2014-02-10T09:11:57.033

you could also replace both continues with elses. (leave the ; where the first one was). – AShelly – 2014-02-10T15:48:25.990

1What's the problem with random()%1? Any int % 1 should be 0. – user253751 – 2014-02-12T03:41:53.017

19

Ruby, 168

Slightly shorter take using an array indexing strategy:

z='qwertyuiop.asdfghjkl...zxcvbnm'+?.*11
gets.chars{|c|$_=z[c]?z:z.upcase
h=[1,-1,11,-11].map{|d|$_[d+~/#{c}/]}-[?.]rescue[]
$><<(rand<0.9?c:[c*2,'',*h.sample].sample)}

Original regular expression version (184):

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

Paul Prestidge

Posted 2014-02-09T19:51:09.033

Reputation: 2 390

3

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?

– user2846289 – 2014-02-10T18:21:38.340

@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! – Paul Prestidge – 2014-02-10T21:41:08.580

Perfect now. Thank you. – user2846289 – 2014-02-10T23:02:50.827

9

Python, 251

from random import*
w=choice
o=ord
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

Kaya

Posted 2014-02-09T19:51:09.033

Reputation: 710

2Some 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 – 2014-02-10T02:03:29.143

1You can do w=__import__('random').choice (at least in Python 3 afaik). – SimonT – 2014-02-10T03:55:22.077

@SimonT ahh, but unfortunately len("w=__import__('random').choice")=29 while len("from random import*;w=choice")=28. – Kaya – 2014-02-10T05:02:55.307

1This code breaks with several text-characters: ?;:< etc – Dhara – 2014-02-10T12:23:11.387

1Also, it has an off-by-one error in indexing: 'b' in 'bbbbbbbb' are replaced by 'x', 'zzzzzzzzzz' gives an index out of bounds – Dhara – 2014-02-10T12:29:02.773

Nice catch @Dhara. I managed to fix the problems by changing by ord(z)&31-1 to (ord(z)&31)-6. The second expression will only return number in the range -6 to 25 and therefore will not return an out of bounds exception when trying to index the array. Now characters like ?<;: grab bogus results from the array which are then thrown out by *isalpha(z). Of course this required reordering the array, but thankfully that doesn't increase the char count. – Kaya – 2014-02-10T16:24:50.117

@Kaya you can further improve by changing the [z]9 to [z]27. Then, you just have to use choice once in the outer-most scope, not separately for the 3 cases. – Dhara – 2014-02-11T08:15:36.007

1Use Python 3's input() and print() to save 2 chars. – Cees Timmerman – 2014-02-11T14:07:16.063

8

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!

Hand-E-Food

Posted 2014-02-09T19:51:09.033

Reputation: 7 912

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 – 2014-02-10T00:23:02.030

@Xantix, I know, but they never said it had to be a program. Either way, my answer now includes program wrappings. – Hand-E-Food – 2014-02-10T00:45:37.050

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 – 2014-02-10T00:46:20.723

2Hmm, 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 – 2014-02-11T00:13:40.240

8

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:''
for(a=0;!a;)a=b[x+[11,-11,1,-1][~~(r()*4)]]
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 = b.search(d);  // x marks the spot
      } else {
        b = b.toUpperCase();
        x = b.search(d);
      }

      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
}

Not that Charles

Posted 2014-02-09T19:51:09.033

Reputation: 1 905

Bravo! JS ninja awarded! – Sunny R Gupta – 2014-02-10T10:13:03.403

1@SunnyRGupta Thanks! Wish I could get it down more. I think the massive parentheses hell might make it longer than needed. – Not that Charles – 2014-02-10T16:41:42.930

Also try to display the non-minified version for novices! – Sunny R Gupta – 2014-02-11T07:35:40.210

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 – 2014-02-13T12:42:33.490

6

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 typos.pl
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:

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

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

user2846289

Posted 2014-02-09T19:51:09.033

Reputation: 1 541

1There'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 – 2014-02-11T10:43:59.877

1The 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 – 2014-02-11T11:01:24.620

1Oh, 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 – 2014-02-11T11:05:59.703

@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. – user2846289 – 2014-02-12T00:16:57.697

1I'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 – 2014-02-12T00:49:10.060

I managed to edit to -7, not -1 ;-). Thanks for help. – user2846289 – 2014-02-12T03:04:14.450

4

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.

Ismael Miguel

Posted 2014-02-09T19:51:09.033

Reputation: 6 797

It doesn't seem to affect capital letters at all. – r3mainer – 2014-02-09T22:26:32.807

1The capital letters are unaffected in the example. But yes, it doesn't. But also notice that I said that it KINDA works. – Ismael Miguel – 2014-02-09T23:32:13.340

3

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 + "";
    }
}

Xantix

Posted 2014-02-09T19:51:09.033

Reputation: 141

3

PHP, 326 320 318 315 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=x.$argv[1];for(;$d=$a[++$b];)echo!rand(0,9)&&($c=ord($d)-65)?(!($g=rand(0,($e=($c>-1&&$c<26)or$c>31&&$c<58)+1))?$d.$d:($g<2?"":(($j=$i[rand(0,strlen($i=$h[$c-!$e*32]))])&&$e?strtoupper($j):$j))):$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
// $i   current character in $h
// $j   temporary var for uppercasing

// 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);
// input from argument
$a=x.$argv[1];

for(;$d=$a[++$b];)
    echo!rand(0,9)&&($c=ord($d)-65)? /* 10% chance, read char ASCII value - 65 into $c */
        (!($g=rand(0,($e=($c>-1&&$c<26)or$c>31&&$c<58)+1))?
          /* random number from 0 to 2 (if alphabetic) or 0 to 1 stored in $g */
            $d.$d: /* double char if $g = 0 */
            ($g<2?
                "": /* omit char if $g = 1*/
                (($j=$i[rand(0,strlen($i=$h[$c-!$e*32]))])&&$e?
                  /* $j = random neighbour of the current char */
                    strtoupper($j): /* uppercase $j */
                    $j)))
        :$d; /* keep char */

Still could be improved, I suppose.

-2, -3 thanks to Ismael Miguel

Aurel Bílý

Posted 2014-02-09T19:51:09.033

Reputation: 1 083

1Where 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 – 2014-02-11T09:24:21.667

1Where 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 – 2014-02-13T20:15:04.427

2

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

Usage:

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.
                }
            }
        }
        System.out.println(z);
    }
}

Olivier Grégoire

Posted 2014-02-09T19:51:09.033

Reputation: 10 647

2

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
{
k:={1:"q",2:"w",3:"e",4:"r",5:"t",6:"y",7:"u",8:"i",9:"o",10:"p",21:"a",22:"s",23:"d",24:"f",25:"g",26:"h",27:"j",28:"k",29:"l",42:"z",43:"x",44:"c",45:"v",46:"b",47:"n",48:"m"},a:=A_LoopField,q:=r(z?3:2),z=
if r(10)!=10{
h.=a
continue
}
for x,y in k
z:=y=a?x:z
if q=1
h.=a a
if q=3
{
Loop{
t:=r(4),w:=z+(t=1?20:t=2?-20:t=3?1:-1)
} until k.HasKey(w)
h.=k[w]
}
}
throw % h
r(n){
Random,w,1,n
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.)

k:={1:"q",2:"w",3:"e",4:"r",5:"t",6:"y",7:"u",8:"i",9:"o",10:"p",21:"a",22:"s",23:"d",24:"f",25:"g",26:"h",27:"j",28:"k",29:"l",42:"z",43:"x",44:"c",45:"v",46:"b",47:"n",48:"m"}
loop, parse, 1
{
    a:=A_LoopField
    ;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
    {
        h.=a
        continue
    }

    ;check if the current character is in the k
    z=
    for x,y in k
        z:=y=a?x:z

    ;choose a random number to decide what typo to do
    q:=r(z?3:2)
    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
        Loop
        {
            t:=r(4)
            w:=z+(t=1?20:t=2?-20:t=3?1:-1)
        } until if k.HasKey(w)
        h.=k[w]
    }
}
;display the string as an error message
throw % h
r(n)
{
    Random,w,1,n
    return w
}

Person93

Posted 2014-02-09T19:51:09.033

Reputation: 171

With which programs does this work? – Ismael Miguel – 2014-02-13T12:38:36.290

It is run by AutoHotkey.exe. http://www.autohotkey.com/

– Person93 – 2014-02-13T16:24:13.790