1

How can you implement the "old" trick of scrambling the internal letters of words?

For those of you who don't know it Wikipedia describes it well.

As mentioned in the comment to this question this has had some research into the "research" originally mentioned in the earliest form of this meme.

Community
  • 1
  • 1
Mark Hurd
  • 10,665
  • 10
  • 68
  • 101

2 Answers2

1

I implemented this in "one" line of VB:

Dim outText = Regex.Replace(inText, _
        "\b([a-zA-z])([a-zA-Z]+)([a-zA-Z])\b", _
        Function(g) (g.Groups(1).Value & String.Join("", _
            (g.Groups(2).Value.ToCharArray.OrderBy( _
                            Function(c) (Rnd(1))) _
                            )) & _
            g.Groups(3).Value))

A better solution would provide a 'more correct' Function for OrderBy that would return the same value for a particular character in a string, but in this case, simply setting the Rnd seed would do to get (somewhat) repeatable results.

(Note that setting the Function to be directly dependent upon the c provided means all internal characters are reordered according to some random ordering, so all internal repeated letters are always grouped together in the scrambled words.)

An example of the output:

(Note that sttenig the Fictunon to be drcteily dpeednent uopn the c previodd mnaes all inratnel cthcearras are roeerredd aindorccg to smoe ronadm oidrreng, so all ietnnarl reteaepd ltteers are awayls guorped tgtheoer in the srlmceabd wodrs.)

Mark Hurd
  • 10,665
  • 10
  • 68
  • 101
  • Nice. Is there an easy way to get the index of the character into the function? Just wondering because then you could create a deterministic function that wouldn't necessarily group together duplicate characters. I know you could do it by having an external counter that you increment but that is not a very pretty technique. :) – Chris Sep 01 '12 at 11:20
  • @Chris: Yes, especially if you expanded the outer `Function` to a standalone, or multi-line, function: the `Groups`, which are `Captures`, contain the `Index` of the match in the original string, so more could be done to provide a "proper" and/or repeatable `Function` for `OrderBy`. – Mark Hurd Sep 02 '12 at 04:17
1

Answer by Mark Hurd is flawed. Even with the problem with duplicate letters corrected, the use of the sort algorithm does not yield a valid result. // See http://okmij.org/ftp/Haskell/perfect-shuffle.txt

Here is my attempt, using recursion. Very simple and easy to understand, but performance could be improved. Obviously it does not use regex, vb.net or linq (see tags). I leave that to the reader.

Random _rng = new Random();

string Scramble(string text) {
  return String.Concat(text[0], Shuffle3(text.Substring(1, text.Length - 2)), text[text.Length - 1]);
}

string Shuffle3(string text) {
  return ShuffleStep(text, _rng.Next(text.Length));
}

string ShuffleStep(string text, int i) {
  return (text.Length == 1) ? text : text[i] + ShuffleStep(text.Remove(i, 1), _rng.Next(text.Length-1));
}
david.pfx
  • 10,520
  • 3
  • 30
  • 63
  • I have implemented an `.OrderRandomly` extension method using the correct shuffle you've pointed out, but as I've used VB.NET without `Yield` it isn't worth putting it up here. – Mark Hurd Oct 05 '12 at 15:48