Reverse words without changing capitals or punctuation

13

1

Create a program with the lowest amount of characters to reverse each word in a string while keeping the order of the words, as well as punctuation and capital letters, in their initial place.

By "Order of the words," I mean that each word is split by a empty space (" "), so contractions and such will be treated as one word. The apostrophe in contractions should stay in the same place. ("Don't" => "Tno'd").

(Punctuation means any characters that are not a-z, A-Z or whitespace*).

  • Numbers were removed from this list due to the fact that you cannot have capital numbers. Numbers are now treated as punctuation.

For example, for the input:

Hello, I am a fish.

it should output:

Olleh, I ma a hsif.

Notice that O, which is the first letter in the first word, is now capital, since H was capital before in the same location.

The comma and the period are also in the same place.

More examples:

This; Is Some Text!

would output

Siht; Si Emos Txet!

Any language can be used. The program with the lowest amount of characters wins.

nasonfish

Posted 2013-04-07T03:21:52.237

Reputation: 163

@nasonfish Just reversing would be too broad to remain open? – Erik the Outgolfer – 2016-04-26T17:58:34.307

@ΈρικΚωνσταντόπουλος Just reversing, without having to pay attention to punctuation/spaces, doesn't seem like a good problem to golf; many languages have something like string.reverse() which could solve the whole problem for them without much effort or room for improvement. The goal was to have a problem that's a bit of a challenge to do in the first place - reversing some characters while keeping others still - and then more of a challenge to condense. – nasonfish – 2016-04-30T13:28:04.300

3How should contractions be treated? That is does Don't touch that! map to t'noD hcuot taht! or to noD't hcuot taht!? – dmckee --- ex-moderator kitten – 2013-04-07T04:39:40.663

2@dmckee "(Punctuation means any characters that are not a-z, A-Z, 1-9 or whitespace)" – John Dvorak – 2013-04-07T04:46:11.247

1@dmckee so it should map to Nod't hcuot tath! – John Dvorak – 2013-04-07T04:49:34.433

1Reversing each word is easy. Reversing each word and keeping capitalisation is not. – John Dvorak – 2013-04-07T04:53:25.140

1Yup, that's the challenge ;) just simply reversing them would be too simple and would likely come down to the language used. This is meant to make you think. – nasonfish – 2013-04-07T04:56:17.393

I've added clarification on contractions, as well as spaces/words, in the second paragraph. – nasonfish – 2013-04-07T04:57:16.473

Now, after the edit, it's getting much more interesting :-o – John Dvorak – 2013-04-07T05:17:25.857

What case should be letters that replace a digit? Should S'm00ch1e become E'1hc00ms or E'1HC00Ms? I suggest treating digits as punctuation: E'h00cm1s – John Dvorak – 2013-04-07T05:20:27.433

That is a good point; would it be bad if I changed the question now to treat digits as punctuation now, after the question has been up for a while? – nasonfish – 2013-04-07T05:25:59.887

I don't think it would be bad – John Dvorak – 2013-04-07T05:28:47.893

I wouldn't call it changing a question – John Dvorak – 2013-04-07T05:35:21.597

Okay, well, I've changed the question to include that. Thanks for pointing it out. – nasonfish – 2013-04-07T05:37:57.363

Perhaps "as well as punctuation and capital letters" would read better "as well as punctuation and positions where letters are capitalized". – DavidC – 2013-04-07T12:40:22.330

Whitespace is kept in place and thus treated as punctuation. Thus "Punctuation means any characters that are not a-z, A-Z or whitespace*" should read "Punctuation means any characters that are not in a-z or A-Z." – DavidC – 2013-04-07T12:43:51.670

@DavidCarraher, Whitespace characters are still special as they separate words, otherwise “Don't touch it!” would become “tih'c uottn oD!”. If you want to rephrase that way, you have to add that “punctuations are kept in place relative to the word, whitespaces are kept in place relative to the string”. – manatwork – 2013-04-08T09:48:47.777

What about numbers 0-9? are they reversed or kept as is? – microbian – 2014-01-29T21:09:44.950

Answers

7

GolfScript, 58 54 48 characters

" "/{.{65- 223&26<}:A,\{.A{96&\)31&@+}*}%+}%" "*

This is a GolfScript solution which became rather long. Lots of the code is actually finding out if a character is in a-zA-Z. Maybe someone can find an even shorter way of testing it.

You can try the code online. Examples:

> Hello, I am fish.
Olleh, I ma hsif.

> This; Is Some Text!
Siht; Si Emos Txet!

> Don't try this at home.
Tno'd yrt siht ta emoh.

Howard

Posted 2013-04-07T03:21:52.237

Reputation: 23 109

That online golfscript editor looks useful. Bookmarking, thanks – John Dvorak – 2013-04-07T11:00:33.700

You can pull the final " " inside the % to save one. I've found other ways of testing a-zA-Z for 11 chars, but none yet for 10. – Peter Taylor – 2013-04-10T07:08:09.397

4

Coffeescript, 134 133 characters

alert prompt().replace /\S+/g,(x)->c=x.match r=/[a-z]/gi;return x.replace r,(y)->return c.pop()[`(y<"a"?"toUpp":"toLow")`+"erCase"]()

Coffeescript is (for the purposes of code golf) a slightly denser version of javascript. It doesn't have the ternary operator, but it has an escape to javascript.

Here's the javascript version:

Javascript, 152 151 characters

alert(prompt().replace(/\S+/g,function(x){c=x.match(r=/[a-z]/gi);return x.replace(r,function(y){return c.pop()[(y<"a"?"toUpp":"toLow")+"erCase"]()})}))

Indented:

alert(prompt().replace(/\S+/g,function(x){
  c=x.match(r=/[a-z]/gi);
  return x.replace(r, function(y){
    return c.pop()[(y<"a"?"toUpp":"toLow")+"erCase"]()
  })
}))

John Dvorak

Posted 2013-04-07T03:21:52.237

Reputation: 9 048

4

APL 69

Takes screen input via: t←⍞

⎕av[1↓∊(↑¨v),¨((¯1×⌽¨z)+z←¯32×~1↓¨v>97)+¨⌽¨1↓¨v←(+\v<66)⊂v←0,⎕av⍳t←⍞]

Graham

Posted 2013-04-07T03:21:52.237

Reputation: 3 184

Shouldn't APL be counted in UTF-8 bytes? :-) – John Dvorak – 2013-04-07T10:40:48.143

@JanDvorak The APL+Win V5 character set is single byte. I have to convert to UTF-8 to post here in order for the characters to render correctly. ⎕av⍳t above returns an index into the character set from 0-255 for the characters in the vector t. – Graham – 2013-04-07T10:50:22.983

2

Ruby: 89 characters (including 1 for the -p switch)

Not copied Jan Dvorak's CoffeeScript solution, but after many attempts my code ended looking like an exact copy. A subconscious voice probably kept whispering “follow the white rabbit Jan Dvorak”. So upvotes for the algorithm should go to his answer.

$_.gsub!(/\S+/){|m|l=m.scan r=/[a-z]/i;m.gsub(r){|c|l.pop.send c<?a?:upcase: :downcase}}

Sample run:

bash-4.2$ ruby -p reverse-word.rb <<< "Hello, I am a fish.
This; Is Some Text!
Don't touch that!
S'm00ch1e"
Olleh, I ma a hsif.
Siht; Si Emos Txet!
Tno'd hcuot taht!
E'h00cm1s

manatwork

Posted 2013-04-07T03:21:52.237

Reputation: 17 865

0

Lua, 143

print(((io.read"*l"):gsub("%w+",function(s)local r=""for i=1,#s do r=("")[s:byte(-i)>96 and"lower"or"upper"](s:sub(i,i))..r end return r end)))

mniip

Posted 2013-04-07T03:21:52.237

Reputation: 9 396

Nice try, but it should also keep punctuation in place: http://pastebin.com/X8QLf6fW

– manatwork – 2013-04-08T10:08:50.210

EDIT: oh i see now – mniip – 2013-04-08T19:24:24.440

-1

EcmaScript 6 (112 characters)

The input is provided in s.

alert(s.replace(/\S+/g,x=>(_=x.match(X=/[a-z]/gi),x.replace(X,a=>_.pop()[(a<"a"?"toUpp":"toLow")+"erCase"]()))))

Based on @Jan Dorvak's answer.

Toothbrush

Posted 2013-04-07T03:21:52.237

Reputation: 3 197

-2

C# (375)

 public static string rev(string s)
    {
        var r = new Regex("[^A-za-z]");

        var result = "";
        var token = "";
        foreach (var c in s)
        {
            if (!r.IsMatch(c + ""))
            {
                token += c;
            }
            else
            {
                result += new string(token.Reverse().ToArray());
                result += c;
                token = "";
            }
        }

        var arr = result.ToArray();
        int i = 0;
        foreach (var c in s)
        {
            arr[i] = char.IsUpper(c) ? char.ToUpper(arr[i]) : char.ToLower(arr[i]);
            i++;
        }

        result = new string(arr);
        return result;
    }

Minified

public static string rev(string s){var r=new Regex("[^A-za-z]");var result="";var token="";foreach(var c in s){if(!r.IsMatch(c+"")){token+=c;}else{result+=new string(token.Reverse().ToArray());result+=c;token="";}}var arr=result.ToArray();int i=0;foreach(var c in s){arr[i]=char.IsUpper(c)?char.ToUpper(arr[i]):char.ToLower(arr[i]);i++;}result=new string(arr);return result;}

microbian

Posted 2013-04-07T03:21:52.237

Reputation: 2 297

Shouldn't it be A-Za-z? – Cyoce – 2016-02-27T20:30:01.110

@Cyoce A little detail: [A-z] is not [A-Za-z]. The first one is a common (?) mistake, 'cause it contains non-alphabetic characters. – Erik the Outgolfer – 2016-04-26T18:06:23.240

1Also shouldn't this be, erm, golfed? – Cyoce – 2016-04-28T22:01:11.030