Cambridge Transposition

21

2

I'm sure most, if not all, of you have come across this at some point or another:

Aoccdrnig to a rscheearch at Cmabrigde Uinervtisy, it deosn't mttaer in waht oredr the ltteers in a wrod are, the olny iprmoetnt tihng is taht the frist and lsat ltteer be at the rghit pclae. The rset can be a toatl mses and you can sitll raed it wouthit porbelm. Tihs is bcuseae the huamn mnid deos not raed ervey lteter by istlef, but the wrod as a wlohe.

  • Create a program that inputs any amount of text. For testing purposes, use the unscrambled version of the above text, found below.

  • The program must then randomly transpose the letters of each word with a length of 4 or more letters, except the first and last letter of each word.

  • All other formatting must remain the same (capitalization and punctuation, etc.).

Testing text:

According to a researcher at Cambridge University, it doesn't matter in what order the letters in a word are, the only important thing is that the first and last letter be at the right place. The rest can be a total mess and you can still read it without problem. This is because the human mind does not read every letter by itself but the word as a whole.

As usual, this is a code-golf. Shortest code wins.

jdstankosky

Posted 2012-12-20T15:38:05.687

Reputation: 1 474

2

Similar to How to randomize letters in a word, though in that one only a single word needs to be scrambled whereas here it's every word in a sentence.

– Gareth – 2012-12-20T16:44:46.500

I agree. The questions are similar enough that solutions for one problem can be used almost directly for the other. – primo – 2012-12-20T17:25:57.237

1Last letter is not right in rscheearch in your sample text. – daniero – 2012-12-20T19:26:35.353

@Daniero it isn't my typo, but it is a known typo (see the link). I left the [sic] out of the quotes. – jdstankosky – 2012-12-20T21:21:12.640

10I'd be more impressed with a program that did the reverse (i.e. input is the scrambled text). – Mr Lister – 2012-12-21T13:38:54.720

1Must the position of the apostrophe in don't remain in the same position? The spec says All other formatting must remain the same (capitalization and punctuation, etc.). but I'm not sure how that works out here... – Gaffi – 2013-03-20T17:25:23.067

Answers

9

Ruby - 50 48 chars, plus -p command line parameter.

gsub(/(?<=\w)\w+(?=\w)/){[*$&.chars].shuffle*''}

Thanks @primo for -2 char.

Test

➜  codegolf git:(master) ruby -p 9261-cambridge-transposition.rb < 9261.in
Acdrcinog to a racreseher at Cagribmde Ursvetniiy, it dsoen't mttaer in waht odrer the leertts in a word are, the olny ionarpmtt tnhig is that the fsirt and last letetr be at the rghit pcale. The rset can be a taotl mses and you can slitl raed it wthiuot perlbom. Tihs is buaecse the hmuan mind does not raed ervey lteetr by ietlsf but the word as a wlhoe.

Wile E. Coyote

Posted 2012-12-20T15:38:05.687

Reputation: 943

3tell me more about this codegolf script – Sparr – 2016-02-02T17:27:47.067

1Ruby doesn't support \K for zero-width look-behind assertion? Also, the innermost grouping is unnecessary, using $& instead of $1. – primo – 2012-12-20T17:47:10.977

@primo, I think not, it doesn't work, and neither have I found it in any reference page. Thanks for $& tip :) – Wile E. Coyote – 2012-12-20T18:17:57.423

You're right. I guess I assumed they had taken perl regex directly, as php does ;) – primo – 2012-12-20T19:01:53.680

1Many years later, but: There is no need to create a new array before the shuffle: [*$&.chars] => $&.chars, saving 3 bytes. – daniero – 2018-07-17T01:02:03.843

Also many years later: Ruby does support the \K operator. I’m too lazy too look up when it was added. – Jordan – 2018-09-16T15:28:47.473

5

Python, 118

Python is terribly awkward for things like this!

from random import*
for w in raw_input().split():l=len(w)-2;print l>0and w[0]+''.join((sample(w[1:-1],l)))+w[-1]or w,

Bonus

I tried some other things that I thought would be clever, but you have to import all sorts of things, and a lot of methods don't have return values, but need to be called separately as its own statement. The worst is when you need to convert the string to a list and then joining it back to a string again.

Anyways, here are some of the things that I tried:

Regex!
import re,random
def f(x):a,b,c=x.group(1,2,3);return a+''.join(random.sample(b,len(b)))+c
print re.sub('(\w)(\w+)(\w)',f,raw_input())
Permutations!
import itertools as i,random as r
for w in raw_input().split():print''.join(r.choice([x for x in i.permutations(w)if w[0]+w[-1]==x[0]+x[-1]])),
You can't shuffle a partition of a list directly and shuffle returns None, yay!
from random import*
for w in raw_input().split():
 w=list(w)
 if len(w)>3:v=w[1:-1];shuffle(v);w[1:-1]=v
 print ''.join(w),

daniero

Posted 2012-12-20T15:38:05.687

Reputation: 17 193

4

PHP 84 bytes

<?for(;$s=fgets(STDIN);)echo preg_filter('/\w\K\w+(?=\w)/e','str_shuffle("\0")',$s);

Using a regex to capture words that are at least 4 3 letters long, and shuffling the inner characters. This code can handle input with multiple lines as well.

If only one line of input is required (as in the example), this can be reduced to 68 bytes

<?=preg_filter('/\w\K\w+(?=\w)/e','str_shuffle("\0")',fgets(STDIN));

There's only one letter in the middle, so it doesn't matter if you shuffle it.

primo

Posted 2012-12-20T15:38:05.687

Reputation: 30 891

3

Retina, 10 bytes

?V`\B\w+\B

Try it online!

Hey, this old challenge was made for the new Retina!

Explanation

\B\w+\B matches groups of letters between non-boundaries, that is groups of letters that don't begin or end a word. Since regexes are greedy, this will match all the letters of a word except the first and the last one.

V is the "reverse" stage, that reverses the order of characters in each match of the regex. With the ? option it scrambles them instead.

Leo

Posted 2012-12-20T15:38:05.687

Reputation: 8 482

I happened across this after finding another 10-byte solution.

– FryAmTheEggman – 2019-10-27T20:03:35.803

3

J (48)

''[1!:2&4('\w(\w+)\w';,1)({~?~@#)rxapply 1!:1[3

Explanation:

  • 1!:1[3: read all input from stdin
  • rxapply: apply the given function to the portions of the input that match the regex
  • ({~?~@#): a verb train that shuffles its input: # counts the length, this gets applied to both sides of ? giving N distinct numbers from 0 to N, { then selects the elements at those indices from the input array.
  • ('\w(\w+)\w';,1): use that regex but only use the value from the first group
  • [1!:2&4: send unformatted output to stdout
  • ''[: suppress formatted output. This is necessary because otherwise it only outputs that part of the output that fits on a terminal line and then ends with ....

marinus

Posted 2012-12-20T15:38:05.687

Reputation: 30 224

1

VBA, 351 373/409

Sub v(g)
m=1:Z=Split(g," "):j=UBound(Z)
For u=0 To j
t=Z(u):w=Len(t):l=Right(t,1):If Not l Like"[A-Za-z]" Then w=w-1:t=Left(t,w):e=l Else e=""
If w>3 Then
n=Left(t,1):p=w-1:s=Right(t,p):f=Right(t,1)
For p=1 To p-1
q=w-p:r=Int((q-1)*Rnd())+1:n=n & Mid(s,r,1):s=Left(s,r-1) & Right(s,q-r)
Next
Else
n=t:f=""
End If
d=d & n & f & e & " "
Next
g=d
End Sub

Alternate (larger) Method:

Sub v(g)
m=1:Z=Split(g," "):j=UBound(Z)
For u=0 To j
t=Split(StrConv(Z(u),64),Chr(0)):w=UBound(t)-1:l=Asc(t(w)):If l<64 Or (l>90 And l<97) Or l>122 Then e=t(w):w=w-1 Else e=""
If w>3 Then
n=t(0):p=w-1:s=""
For i=-p To -1
s=t(-i) & s
Next
f=t(w)
For p=1 To p-1
r=Int((w-p)*Rnd())+1:n=n & Mid(s,r,1):s=Left(s,r-1) & Right(s,w-p-r)
Next
n=n & s
Else
n=Z(u):f="":e=""
End If
d=d & n & f & e & " "
Next
g=d
End Sub

Both of these methods change the value of the variable passed to the Sub. i.e.

Sub Test()
strTestString = "This is a test."
v strTestString
Debug.Print strTestString
End Sub

will output something like this:

"Tihs is a tset."

Also, this does randomize mid-word punctuation, so this may not fit the spec 100%.

Gaffi

Posted 2012-12-20T15:38:05.687

Reputation: 3 411

1

APL NARS 172 chars

r←g x;i;s;d;k
s←⎕AV[98..123]∪⎕A
i←1⋄v←''⋄r←''⋄k←⍴x
A:d←''⋄→C×⍳i>k⋄d←x[i]⋄→C×⍳∼d∊s⋄v←v,d⋄i+←1⋄→A
C:v←{t←¯2+⍴r←⍵⋄t≤1:r⋄r[1+t?t]←⍵[1+⍳t]⋄r}v
r←∊r,v,d
v←''⋄i+←1⋄→A×⍳i≤k
g x←⍞

13+17+18+44+41+8+17+5+9=172; This function g() has input as a string; has output as a string. I add the input command because i don't know how insert \' in a quoted string. Commented

∇r←g x;i;s;d;k
   ⍝ words are element of  a-zA-Z separed from all other
   s←⎕AV[98..123]∪⎕A ⍝a-zA-Z ascii ⎕IO = 1
   i←1⋄v←''⋄r←''⋄k←⍴x
A:   d←''⋄→C×⍳i>k⋄d←x[i]⋄→C×⍳∼d∊s⋄v←v,d⋄i+←1⋄→A
C:      v←{t←¯2+⍴r←⍵⋄t≤1:r⋄r[1+t?t]←⍵[1+⍳t]⋄r}v
        r←∊r,v,d
        v←''⋄i+←1⋄→A×⍳i≤k
∇

result

g x←⍞
According to a researcher at Cambridge University, it doesn't matter in what order the letters in a word are, the only important thing is that the first and last letter be at the right place. The rest can be a total mess and you can still read it without problem. This is because the human mind does not read every letter by itself but the word as a whole.
  Androiccg to a rhraeecser at Cgirbdmae Uirevtsiny, it deson't mtetar in waht oderr the ltrtees in a wrod are, the olny intro
  apmt tinhg is taht the frsit and lsat lteter be at the rghit pacle. The rset can be a ttaol mses and you can siltl rae
  d it wtuhoit poeblrm. Tihs is bcsauee the hmaun mnid deos not raed eervy lteter by isletf but the wrod as a wolhe.

RosLuP

Posted 2012-12-20T15:38:05.687

Reputation: 3 036

1

PHP 7.1, not competing, 80 bytes

for(;$w=$argv[++$i];)echo$w[3]?$w[0].str_shuffle(substr($w,1,-1)).$w[-1]:$w," ";

takes input from command line arguments. Run with -nr. (will obviously fail at punctuation)

Titus

Posted 2012-12-20T15:38:05.687

Reputation: 13 814

1

PHP, 94+1 bytes

+1 for -R flag

<?=preg_replace_callback("/(?<=\w)\w+(?=\w)/",function($m){return str_shuffle($m[0]);},$argn);

Pipe input through php -nR '<code>'.

Note: preg_replace_callback came to PHP in 4.0.5; closures were introduced in php 5.3;
so this requires PHP 5.3 or later.

Unfortunately, the match is always sent as an array, even if there are no sub patterns,
thus I cannot just use str_shuffle as the callback, which would save 29 bytes.

Titus

Posted 2012-12-20T15:38:05.687

Reputation: 13 814

1

JavaScript, 76 67 bytes

thanks to Arnauld for -9 bytes.

t=>t.replace(/\B\w+\B/g,m=>[...m].sort(_=>Math.random()-.5).join``)

Try it online!


Ungolfed

t =>                  // function with a single argument
     t.replace(       // Replace ...
         /\B\w+\B/g,  // every match of the regex
         m => ...     // with the return value of the replacement function
     )

/       /g            // Match all occurences of
   \w+                // 1 or more word chars ...
 \B   \B              // ... that aren't on the beginning or end of the word

m =>                  // Replacement function
     [...m]           // convert matched string to a list of chars
       .sort(_ => Math.random()-.5) // sort with a random comparision function
       .join``        // join the list into a single string

ovs

Posted 2012-12-20T15:38:05.687

Reputation: 21 408

Note that "shuffle by doing sort like that is not uniform"

– user202729 – 2018-08-05T15:40:09.010

You can use /\B\w+\B/g. (But for the bounty, note that code length isn't important.) – Arnauld – 2018-08-05T19:54:12.397

1@Arnauld thanks a lot. As this is still codegolf, every byte counts. – ovs – 2018-08-05T21:10:15.027

@Arnauld Serious contender rule still applies. – user202729 – 2018-08-06T12:03:15.880

The "Try it online" redirects me to "JavaScript (Node.js)". Will this work in pure, no-Node.js depended JavaScript run as i.e. script inside some HTML file, in a browser? Second thing, as I think the original rules for Cambridge Transposition were a bit different than showed here (in OP question). Is it possible to modify your code to scramble words 5+ letters long (instead of 4+ letters long, as in OP's question)? – trejder – 2018-08-06T14:43:05.737

1@trejder I added an explanation that should help you to modify the code for your needs. In its current form the code should run well in most browsers. If you want to use in this in real code, you should probably change the way it shuffles the characters to a uniform algorithm. – ovs – 2018-08-06T15:23:54.423

For example Fisher-Yates algorithm? 26 bytes more for the replacement function but x=>(l=x.length,g=a=>l?a.splice(l--*Math.random(),1)+g(a):"")([...x]) should be a uniform algorithm. Of course no one would use golfed codes in production lol – Shieru Asakoto – 2018-09-16T10:22:48.543

1

APL 107

Unfortunately my APL interpreter does not support regexs so here's a home rolled version where the text to be scrambled is stored in the variable t:

⎕av[((~z)\(∊y)[∊(+\0,¯1↓n)+¨n?¨n←⍴¨y←(~z←×(~x)+(x>¯1↓0,x)+x>1↓(x←~53≤(∊(⊂⍳26)+¨65 97)⍳v←⎕av⍳,t),0)⊂v])+z×v]

Essentially the code partitions the text into words based on the letters of the alphabet only and then into the letters between the first and last letters of those words. These letters are then scrambled and the whole character string reassembled.

Graham

Posted 2012-12-20T15:38:05.687

Reputation: 3 184

1

APL, 58 49

I believe this works in IBM APL2 (I don't have IBM APL)

({⍵[⌽∪t,⌽∪1,?⍨t←⍴⍵]}¨x⊂⍨~b),.,x⊂⍨b←' ,.'∊⍨x←⍞,' '

If not, then in Dyalog APL, add to the front:

 ⎕ML←3⋄

which adds 6 chars


This assumes the only non-word characters are space, comma, and period.

TwiNight

Posted 2012-12-20T15:38:05.687

Reputation: 4 187

Still golfable, but I don't have APL symbols on iPhone... – TwiNight – 2012-12-28T12:01:13.880

0

Japt, 32 bytes

m@Xl ¨4?Xg0 +Xs1J ö(x) +XgJ:X}" 

Try it online!

Bejofo

Posted 2012-12-20T15:38:05.687

Reputation: 31

Can I run Japt directly in a browser? Without any external libraries, compilers etc.? If not then this unfortunately doesn't count as per bounty rules (need solution that works in pure web browser). Second thing, as I think the original rules for Cambridge Transposition were a bit different than showed here (in OP question). Is it possible to modify your code to scramble words 5+ letters long (instead of 4+ letters long, as in OP's question)? – trejder – 2018-08-06T14:45:11.147

1@trejder All submissions must conform to the rules in the original question. Modifying it like this would make it invalid. – user202729 – 2018-08-07T01:46:27.643

1@trejder Japt can't run directly in a browser without a compiler. Secondly if you replace the 4 in the code with 5 then it should only scramble 5+ letter long words. – Bejofo – 2018-08-07T05:48:35.403

0

Java, 1557 834 bytes Thanks to @JoKing for tips.

A bit late to the competition. Forgot that I had started on this problem.

Golfed

import java.util.*;public class s{ public static void main(String[] args){ Scanner s=new Scanner(System.in);String a=s.next();String[] q=a.split("\\s+");for (int i=0;i<q.length;i++) { q[i]=q[i].replaceAll("[^\\w]", ""); }String f="";for (String z:q) { f+=scramble(z);f+=" "; }System.out.print(f); }private static String scramble(String w){if(w.length()==1||w.length()==2){return w;}char[]l=w.toCharArray();char q=l[w.length()-1];String e=Character.toString(l[0]);char[]n=new char[l.length-2];for(int i=0;i<l.length-2;i++){n[i]=l[i+1];}HashMap<Integer,Character>s=new HashMap<>();int c=1;for(char p:n){s.put(c,p);c++;}HashMap<Integer,Integer>o=new HashMap<>();Random z=new Random();for(int i=0;i<w.length()-2;i++){int m=z.nextInt(n.length);while(o.getOrDefault(m,0) == 1){m=z.nextInt(n.length);}e+=s.get(m+1);o.put(m,1);}return e+=q;}}

Non-golfed

import java.util.HashMap;
import java.util.Random;

public class SentenceTransposition {
    public static void main(String[] args) {
        String input = "According to a researcher at Cambridge University, it doesn't matter in what order the letters in a word are, the only important thing is that the first and last letter be at the right place. The rest can be a total mess and you can still read it without problem. This is because the human mind does not read every letter by itself but the word as a whole.";
        String[] words = input.split("\\s+");
        for (int i = 0; i < words.length; i++) {
            words[i] = words[i].replaceAll("[^\\w]", "");
        }
        String finalsentence = "";
        for (String word : words) {
            finalsentence += scramble(word);
            finalsentence += " ";
        }
        System.out.println(finalsentence);
    }

    private static String scramble(String word) {
        if (word.length() == 1 || word.length() == 2) {
            return word;
        }
        char[] letters = word.toCharArray();
        char lletter = letters[word.length()-1];
        String endword = Character.toString(letters[0]);
        char[] nletters = new char[letters.length-2];
        for (int i = 0; i < letters.length-2; i++) {
            nletters[i] = letters[i+1];
        }
        HashMap<Integer, Character> set = new HashMap<>();
        int count = 1;
        for (char nletter : nletters) {
            set.put(count, nletter);
            count++;
        }
        HashMap<Integer, Integer> chosen = new HashMap<>();
        Random random = new Random();
        for (int i = 0; i < word.length()-2; i++) {
            int cur = random.nextInt(nletters.length);
            while (chosen.getOrDefault(cur,0) == 1) {
                cur = random.nextInt(nletters.length);
            }
            endword += set.get(cur+1);
            chosen.put(cur, 1);
        }
        return endword += lletter;
    }
}

Jaden Lee

Posted 2012-12-20T15:38:05.687

Reputation: 1

It looks like there's a lot of whitespace you can remove. Have you had a look at Tips for golfing in Java? edit: also, you seem to have the input hard-coded. You should be taking input from the user instead

– Jo King – 2018-09-16T05:07:18.123

@JoKing ah ok. I will take input from the user. – Jaden Lee – 2018-09-16T05:11:02.730

I managed to golf this down to 650 bytes before realizing that it doesn't work. – Quintec – 2018-09-16T15:23:07.553

@Quintec do you mean that my code doesn't work? – Jaden Lee – 2018-09-25T03:23:38.013

0

Sidef, 89 85 bytes

Block (anonymous callable):

{.words.map{[_[0],(_.len-1?([_[1..^(_.len-1)]].shuffle...,_[1]):'')].join}.join(' ')}

Output, when used like { ... }('..'):

 I hvae nveer not ocne in my life slleepd nhedatarnel crtreolcy
 I have never not once in my lfie sepelld naetadenrhl ccrtloery

Somewhat ungolfed

.words.map{
  [
    .first,
    (_.len-1
      ? (  [ _[1..^(_.len-1)] ].shuffle..., .last )
      : '')
  ].join
}.join(' ')

cat

Posted 2012-12-20T15:38:05.687

Reputation: 4 989

0

Pyth, 23 bytes

jdm?gld4++hd.<Ptd1eddcz

Non-competing because Pyth was made after this challenge was posted.

Try it online

Downgoat

Posted 2012-12-20T15:38:05.687

Reputation: 27 116

0

R, 179

Using the function I wrote for the randomize letters in a word problem:

Input:

s <- "According to a researcher at Cambridge University, it doesn't matter in what order the letters in a word are, the only important thing is that the first and last letter be at the right place. The rest can be a total mess and you can still read it without problem. This is because the human mind does not read every letter by itself but the word as a whole."

Solution:

f=function(w){l=length;s=strsplit(w,"")[[1]];ifelse(l(s)<3,w,paste(c(s[1],sample(s[2:(l(s)-1)]),s[l(s)]),collapse=""))}
g=Vectorize(f)
paste(g(strsplit(s," ")[[1]]), collapse=" ")

Result:

[1] "Arioccdng to a reehaecrsr at Cabrgimde Uveirisnyt, it des'not mttear in waht odrer the lttrees in a wrod are, the olny inpotmart thnig is that the fsrit and lsat letetr be at the right palce. The rset can be a toatl mses and you can stlil raed it wutioht pmrlebo. This is bsuceae the hmuan mnid deos not read ervey lteetr by iesltf but the word as a wleho."

Paolo

Posted 2012-12-20T15:38:05.687

Reputation: 696