13
\$\begingroup\$

Task

  • The user inputs a sentence - words only. Any input other than letters or spaces, including integers and punctuation, should throw an exception: "Sentence must only use letters".
  • The output has a pattern, where some words are reversed and others words are normal.
  • The pattern starts as a normal word, the next two words are reversed, then the next two words are normal and the pattern continues.
  • An example of where the words should be normal and where words reversed is below:

Normal - Reversed - Reversed - Normal - Normal - Reversed - Reversed - Normal ...

Input Example

She sells Sea shells on the Sea shore

Output Example

She slles aeS shells on eht aeS shore

Additional Rules

  • If capital letters are used, they should remain on the letter they were originally posted on.
  • Any multiple spaces initially posted on input should be reduced to one space. For example Programming Puzzles and Code Golf becomes Programming selzzuP dna Code Golf

Shortest Code Wins!!

Happy coding...

\$\endgroup\$
17
  • 8
    \$\begingroup\$ Many programming languages do not have exceptions. \$\endgroup\$
    – Doorknob
    Oct 30, 2015 at 23:30
  • 15
    \$\begingroup\$ @nimi It seems entirely unnecessary to restrict a challenge to a small subset of languages for such a trivial reason. \$\endgroup\$
    – Doorknob
    Oct 30, 2015 at 23:56
  • 10
    \$\begingroup\$ This otherwise-good challenge is ruined by the rule Any input other than letters or spaces, including integers and punctuation, should throw an exception: "Sentence must only use letters". It means implementing a secondary task totally unrelated to the challenge of reversing words, cuts out languages that don't have exceptions, and requires hardcoding or compressing a long string that takes up a lot of the byte count. \$\endgroup\$
    – xnor
    Oct 31, 2015 at 7:53
  • 2
    \$\begingroup\$ @Belfield Yes, I see your bind. I guess there's nothing you can do now. In the future, try posting in the Sandbox to get feedback before posting. \$\endgroup\$
    – xnor
    Oct 31, 2015 at 8:29
  • 3
    \$\begingroup\$ @Belfield a good challenge is much more difficult than a good answer. I enjoyed this one anyway, and the next wil be better. \$\endgroup\$
    – edc65
    Oct 31, 2015 at 10:19

17 Answers 17

15
\$\begingroup\$

TeaScript, 55 bytes 58 60 69 76 78 80 87 89

xO`a-z `?xl(#~-i&2?l:lv(),/ +/):Ld`SÀZn­ Û § «e Ò5s`

This is extremely short, I'm very happy with it.

The last ~20 characters may seem like gibberish but that's "Sentence must only use letters" encoded. All the characters have char codes below 256 so each are one byte

Explanation

xO`a-z `?  // If input contains only a-z and space...

   xl(#       // Loop through input 
      ~-i&2?  // If (index - 1 "unary and"ed with 2) isn't 0...
          :l,     // Leave alone
          lv()    // Otherwise, reverse string
       / +/ // Loops on spaces
   )

:Ld`SÀZn­ Û § «e Ò5s` // Otherwise... decompress and print  the error string
\$\endgroup\$
5
  • \$\begingroup\$ Thanks for posting the test - very nice. Every one is in the same boat when it comes to the error - no golfing that line \$\endgroup\$
    – Belfield
    Oct 31, 2015 at 0:07
  • \$\begingroup\$ Strange, now it works in Firefox. But I also used Firefox earlier. \$\endgroup\$
    – Jakube
    Oct 31, 2015 at 14:46
  • \$\begingroup\$ Best answer so far! \$\endgroup\$
    – Belfield
    Nov 1, 2015 at 18:26
  • \$\begingroup\$ What? You beat Pyth?! With a JS-based language?!? How is that even possible?!?! \$\endgroup\$ Nov 25, 2015 at 3:12
  • 2
    \$\begingroup\$ @ETHproductions You can always win as long as Dennis isn't competing :p \$\endgroup\$
    – Downgoat
    Nov 25, 2015 at 5:51
4
\$\begingroup\$

Haskell, 141 bytes

r=reverse
f x|all(`elem`(' ':['a'..'z']++['A'..'Z']))x=unwords$zipWith($)(cycle[id,r,r,id])$words x|1<2=error"Sentence must only use letters"

Almost 2/3 of the code is for error checking. Seems to be the first real world challenge.

The work is done by unwords$zipWith($)(cycle[id,reverse,reverse,id])$words x which splits the input into a list of words, zips it with the cycling list of functions [id,reverse,reverse,id,id,reverse...] and joins the result with spaces back to a single string.

Thanks to @Christian Irwan for 2 bytes.

\$\endgroup\$
4
  • \$\begingroup\$ "Sentence must only user letters" can be changed to "Sentence must only use letters" - my bad on the error! \$\endgroup\$
    – Belfield
    Oct 30, 2015 at 23:11
  • \$\begingroup\$ @Belfield: fixed \$\endgroup\$
    – nimi
    Oct 30, 2015 at 23:13
  • \$\begingroup\$ Why don't r=reverse? \$\endgroup\$
    – Xwtek
    Oct 31, 2015 at 15:53
  • \$\begingroup\$ @ChristianIrwan: Thanks! (In an early version I had a pointfree function without a name, so using two times reverse and r=reverse had the same length, because of the missing f=. Didn't check again when moving to non pointfree). \$\endgroup\$
    – nimi
    Oct 31, 2015 at 16:09
3
\$\begingroup\$

JavaScript (ES6) 122

f=s=>/[^a-z ]/i.test(s)?"Sentence must only use letters":s.split(/ +/).map((w,i)=>~-i&2?w:[...w].reverse().join``).join` `

alert(f(prompt('?','She sells Sea shells on the Sea shore')))

\$\endgroup\$
2
  • \$\begingroup\$ When there is a newline in the input, it outputs an error, from the example I don't think this is supposed to happen \$\endgroup\$
    – Downgoat
    Oct 31, 2015 at 1:27
  • 1
    \$\begingroup\$ @Vɪʜᴀɴ it's tricky, The example is about multiple spaces, but then there are no multiple spaces - just 1 newline. I think it was mangled by SO editor. IF we have to manage newlines and other generic space, the byte count increase by 2 \$\endgroup\$
    – edc65
    Oct 31, 2015 at 1:31
2
\$\begingroup\$

Retina, 103 bytes

\s+

(?<=^\S+ (\S+ )?((\S+ ){4})*)
;
+`(;\S*)(\S)
$2$1
;

i`.*[^a-z ].*
Sentence must only use letters

There should be a single space on the second line, which SE seems to be swallowing. Run the code from a single file with the -s flag.

Retina has no concept of exceptions so the output is simply replaced by Sentence must only use letters if there are non-letter non-whitespace characters in the input.

\$\endgroup\$
0
2
\$\begingroup\$

Pyth, 61 bytes

?.A}R+G\ rz0jd.e_W%%k4 3bfTczd"Sentence must only use letters

Try it online.

\$\endgroup\$
2
\$\begingroup\$

Python, 163 160 157 145

k=raw_input()
k=["Sentence tsum ylno use letters",k][k.replace(' ','').isalpha()]
for i,x in enumerate(k.split()):print x[::-1if(i+1)/2%2else 1],

Removed 15 characters, thanks Mego!!

\$\endgroup\$
3
  • \$\begingroup\$ Yes, afraid nimi has a point... \$\endgroup\$
    – Belfield
    Oct 30, 2015 at 23:28
  • \$\begingroup\$ Shoot, I missed that. I'll revise it. \$\endgroup\$
    – Moose
    Oct 30, 2015 at 23:32
  • \$\begingroup\$ @Mego, re.search returns None (which can't be used as an index) if the result isn't found, and adding "!=None" is actually one byte longer than my original method. I saved 3 bytes by merging the last two lines though. Thanks! \$\endgroup\$
    – Moose
    Oct 31, 2015 at 1:11
1
\$\begingroup\$

Bash + coreutils, 108

[ ${@//[a-zA-Z]/} ]&&echo Sentence must only use letters||for t;{
((++i/2%2))&&rev<<<$t||echo $t
}|tr \\n \ 

The last character of this program is a space.

Input is taken from the command line:

$ ./norrevvevnor.sh Programming Puzzles and Code$'\n' Golf
Programming selzzuP dna Code Golf $ 
$ ./norrevvevnor.sh Programming Puzzles and Code$'\n' Golf1
Sentence must only use letters
$ 
\$\endgroup\$
1
\$\begingroup\$

Pyth, 72

=zflTc?:z"[^A-Za-z ]"0"Sentence tsum ylno use letters"zdjd.e?%/hk2 2_bbz

Doesn't beat the other Pyth answer, but I already invested time into writing it. It's basically a translation of my Python answer.

Try it online

\$\endgroup\$
1
\$\begingroup\$

Julia, 109 bytes

s->(i=0;join([isalpha(w)?(i+=1)%4>1?reverse(w):w:error("Sentence must only use letters")for w=split(s)]," "))

i=0 and (i+=1)%4>1 are used to decide whether each word gets reversed or not. isalpha applies to the words after being split using split(s) to determine whether or not there are characters that aren't letters (spaces have already been removed by this point). join restores the string after the manipulation, unless the error is thrown.

\$\endgroup\$
1
\$\begingroup\$

Julia, 150 134 bytes

s->ismatch(r"[^a-z ]"i,s)?error("Sentence must only use letters"):(i=3;join([(i+=1;isodd((i+1)i÷2)?reverse(w):w)for w=split(s)]," "))

Ungolfed:

function f(s::AbstractString)
    if ismatch(r"[^a-z ]"i, s)
        error("Sentence must only use letters")
    else
        i = 3
        a = [(i += 3; isodd((i + 1)i ÷ 2) ? reverse(w) : w) for w = split(s)]
        return join(a, " ")
    end
end

Saved 16 bytes thanks to Glen O!

\$\endgroup\$
4
  • \$\begingroup\$ Before anything else, might I suggest reversing the logic of the initial conditional and assigning r to be its result? That is, r=ismatch(...)||error(...) - will shave off a few characters, and reverse the conditional that uses r. Will comment again with, I suspect, some more savings \$\endgroup\$
    – Glen O
    Oct 31, 2015 at 9:17
  • \$\begingroup\$ Minor correction - I had || to deal with the negation, then realised that the negation isn't necessary. Reverse it back to &&. And even better, use ?: instead to do it even better. s->(r=ismatch(r"[^a-z ]"i,s))?error("Sentence must only use letters"):join([(iseven(i)&&(r=!r);r?reverse(w):w)for(i,w)=enumerate(split(s))]," ") for 144 bytes. And I think I can do better inside join... \$\endgroup\$
    – Glen O
    Oct 31, 2015 at 9:24
  • \$\begingroup\$ Here's a streamlined version of your solution, with 134 bytes: s->ismatch(r"[^a-z ]"i,s)?error("Sentence must only use letters"):(i=3;join([(i+=1;isodd((i+1)i÷2)?reverse(w):w)for w=split(s)]," ")) \$\endgroup\$
    – Glen O
    Oct 31, 2015 at 9:45
  • \$\begingroup\$ @GlenO Awesome suggestions, thanks! \$\endgroup\$
    – Alex A.
    Oct 31, 2015 at 20:48
0
\$\begingroup\$

Pyth, 55 bytes

?--rz0Gd"Sentence must only use letters"jd.e_W%%k4 3bcz

Borrowed the %%k4 3 bit from Pietu1998. Saved one additional byte.

Try it online: Demonstration or Test Suite

Explanation

?--rz0Gd"..."jd.e_W%%k4 3bcz   implicit: z = input string
   rz0                         convert z to lower-case
  -   G                        remove all letters
 -     d                       remove all spaces
?                              if there is some chars left than
        "..."                    print the string "Sentence must only ..."
                               else:
                          cz     split z by spaces or multiple spaces
               .e                map each pair (k index, b string) of ^ to: 
                 _       b          b or reversed of b, depending on
                  W%%k4 3           (k mod 4) mod 3
             jd                  join the result by spaces
\$\endgroup\$
0
\$\begingroup\$

Perl 5 -ap, 80 bytes

map$_=++$i%4>1?reverse:$_,@F;$_=/[^a-z ]/i?"Sentence must use only letters":"@F"

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Java, 215 bytes

Regex is fun

s->{if(s.split("[^a-zA-Z ]").length>1)throw new Error("Sentence must only contains letters");else{int i=1;for(String a:s.split(" "))System.out.print((i++%2<1?new StringBuffer(a).reverse():a)+(a.isEmpty()?"":" "));}}

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ Your output currently isn't correct. You now output She slles aeS shells no the aeS shore, but it should be She slles aeS shells on eht aeS shore instead (first normal; then alternating in pairs of 2 reversed or not). Two issues cause this. You now increase i even if an item is empty, and i++%2<1 should be i++%4>1 instead. Here a fixed 211 bytes version. \$\endgroup\$ Apr 24, 2019 at 12:11
  • \$\begingroup\$ @KevinCruijssen this is what I get for not reading carefully enough \$\endgroup\$ Apr 24, 2019 at 12:45
0
\$\begingroup\$

Jelly, 39 bytes

³Ḳ¹ƇUJ2&TƲ¦K
“*[,ṛDṾȧƤ°Ġṛ©¦»
ØẠ” ṭ³eƇ⁼£

Try it online!

Thanks to Erik the Outgolfer. He saved me from a few extra bytes and from many hours of frustration.

Here's a 46 byte solution

It actually throws a python syntax error when the input contains invalid characters.

³Ḳ¹ƇUJ2&TƲ¦K
“çỤḷṁŀDṀẠṠGmḟĖƲƑ⁽Ḳḟ»ŒV
ØẠ” ṭ³eƇ⁼£

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Japt v2.0a0 -S, 41 bytes

¸¬è\L ?`SÀZn­ Û § «e Ò5s`:UeS²S ¸ËzEc2

Try it

¸¬è\L ?`...`:UeS²S ¸ËzEc2     :Implicit input of string U
¸                             :Split on spaces
 ¬                            :Join
  è                           :Count occurrences of
   \L                         :RegEx /[^A-Z]/gi
      ?`...`:                 :If truthy return the compressed string "Sentence must only use letters", else
             Ue               :Recursively replace in U
               S²S            :  Two spaces with one
                   ¸          :Split on spaces
                    Ë         :Map each element at 0-based index E
                     z        :  Rotate clockwise by 90 degrees multiplied by
                      Ec2     :    E rounded up to the nearest multiple of 2
                              :Implicit output, joined with spaces
\$\endgroup\$
0
\$\begingroup\$

05AB1E, 36 bytes

ðKDáÊi“¸–ƒ—€É€Å™ê“.ªFë#áεN4%>2÷iR]ðý

Try it online.

Throws the following error when the input does not only contain [A-Za-z ]:

(RuntimeError) Could not convert Sentence must only use letters to integer.

Explanation:

ðK                   # Remove all spaces from the (implicit) input-string
  Dá                 # Create a copy, and remove everything except for letters from this copy
    Êi               # If the copy with letters removed and the original are NOT equal:
      “¸–ƒ—€É€Å™ê“   #  Push dictionary string "sentence must only use letters"
                  .ª #  With sentence capitalization
      F              #  And try to loop that many times, causing the error above
     ë               # Else:
      #              #  Split the (implicit) input-string on spaces
       á             #  Only keep letters (which will remove empty items caused by multiple
                     #  adjacent spaces in the input, which is shorter than `õK`)
        ε            #  Map each word to:
         N4%>2÷      #   Calculate ((index modulo-4) + 1) integer-divided by 2
                     #   (results in 0,1,1,2,0,1,1,2,0,1 for indices 0,1,2,3,4,5,6,7,8,9)
               i     #   If this is exactly 1:
                R    #    Reverse the current word
     ]               # Close the if-statement, map, and if-else statement
      ðý             # Join the modified word-list by spaces
                     # (and then output it implicitly as result)

See this 05AB1E tip of mine (section How to use the dictionary?) to understand why “¸–ƒ—€É€Å™ê“ is "sentence must only use letters".

\$\endgroup\$
0
\$\begingroup\$

PHP, 147 bytes

foreach(explode(' ',$argn)as$a){if(!ctype_alpha($a))throw new Exception('Sentence must only use letters');$o.=(++$i%4>1?strrev($a):$a).' ';}echo$o;

Try it online!

Or if die() is acceptable as an "Exception":

PHP, 131 bytes

foreach(explode(' ',$argn)as$a){if(!ctype_alpha($a))die('Sentence must only use letters');$o.=(++$i%4>1?strrev($a):$a).' ';}echo$o;

Try it online!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.