The goal of this challenge is to receive an input and output that input but with sentence order reversed. Example Input:

Hello friend. What are you doing? I bet it is something I want to do too!

Example Output:

I bet it is something I want to do too! What are you doing? Hello friend.

As you can tell from the examples, your program has to deal with question marks, exclamation points, and periods. You can assume each sentence has a punctuation and than a space before the next sentence. Trailing spaces/newlines are ok, as long as it is readable. Shortest code wins.

Good luck!

EDIT: You can assume the sentences has no quotes or parentheses, but if you make your code be able to deal with both of those then you get -5 bytes Example output for parens/quotes:

"Hello, " she said. (I didn't know what she was talking about.) --> (I didn't know what she was talking about.) "Hello, " she said.
  • \$\begingroup\$ Can we assume that there aren't going to be any quotes or parentheses? If not, how do we handle them? \$\endgroup\$ – BrainSteel May 14 '15 at 21:35
  • \$\begingroup\$ Made an edit to the post clearing that up. \$\endgroup\$ – user40734 May 14 '15 at 21:37
  • \$\begingroup\$ Can you give an example of expected output for a sentence containing quotes or parens, please? \$\endgroup\$ – mbomb007 May 14 '15 at 22:10
  • 6
    \$\begingroup\$ If a sentence has punctuation within quotes or parens, how should we deal with it? \$\endgroup\$ – isaacg May 14 '15 at 22:20
  • 2
    \$\begingroup\$ @Scimonster You mean "i.e.", etc., right? Oh, and please amend my test case quote to be: "Hello!" she said. (I hesitated. How should I respond? This is too much!) I responded, "Hi there. How are you? What is your cat's name?" without thinking any more about it. \$\endgroup\$ – Not that Charles May 15 '15 at 6:46

19 Answers 19


Julia, 45 42 bytes - 5 bonus = 37

s->join(reverse(split(s,r"[.?!]\K "))," ")

This creates an anonymous function that accepts a string as input and returns the string with its sentences reversed. This handles any special character appropriately, though double quotes and dollar signs must be escaped, otherwise they aren't valid strings in Julia.

Ungolfed + explanation:

function f(s)
    # Get individual sentences by splitting on the spaces that
    # separate them. Spaces are identified by matching punctuation
    # then moving the position beyond that match and matching a
    # space. This is accomplished using \K.

    sentences = split(s, r"[.?!]\K ")

    # Reverse the order of the array of sentences.

    reversed_order = reverse(sentences)

    # Join the array elements into a string, separated by a space.

    join(reversed_order, " ")


julia> f("Hello friend. What are you doing? I bet it is something I want to do too!")
"I bet it is something I want to do too! What are you doing? Hello friend."

julia> f("\"Hello, \" she said. (I didn't know what she was talking about.)")
"(I didn't know what she was talking about.) \"Hello, \" she said."

And if you don't like looking at the escaped quotes in the output:

julia> println(f("\"Hello, \" she said. (I didn't know what she was talking about.)"))
(I didn't know what she was talking about.) "Hello, " she said.

Saved 3 bytes on the regular expression thanks to Martin Büttner! Previously this used a lookbehind: (?<=[.?!]).

  • \$\begingroup\$ I don't think that this qualifies for the bonus... \$\endgroup\$ – Optimizer May 16 '15 at 8:10
  • \$\begingroup\$ @Optimizer: How does it not? It works as expected with parentheses, quotes, etc. as given in the post. \$\endgroup\$ – Alex A. May 16 '15 at 17:49
  • \$\begingroup\$ Can you provide an online link to test , with the example from the bonus section of the question. \$\endgroup\$ – Optimizer May 16 '15 at 17:53
  • \$\begingroup\$ @Optimizer: The only way to run a recent version of Julia online requires registration and doesn't support permalinks. Would it suffice to simply include input and output here in the post? \$\endgroup\$ – Alex A. May 16 '15 at 17:55
  • \$\begingroup\$ Sure, I guess.. \$\endgroup\$ – Optimizer May 16 '15 at 17:59

CJam, 23 22 bytes

I am not sure if this qualifies for the bonus or not, but here goes the solution:


Code Expansion (bit outdated):

Sq+                      e# Read the input and prepend with a space
   {            }%       e# For each input character
    _".?!"&              e# Copy and check if its one of ., ? and !
           {][}&         e# If it is one of the above, wrap everything till now in an array
                         e# and start a new array to be wrapped next time we get one of those
                         e# three characters. We now have an array of strings, each having
                         e# a single sentence
                  W%     e# Reverse the ordering of these sentences
                    s(   e# Convert to string and remove the first space

Try it online here

  • \$\begingroup\$ Ah, you made this post right after I edited it at first. You get a -5 bonus now (Just to make it a little harder) So -5 bonus to you! 18 bytes, wow, not sure if thats beatable :P \$\endgroup\$ – user40734 May 14 '15 at 21:41

J, 35 32

It almost handles bonus input, except I have to escape single apostrophes, so I guess it doesn't count. (Also, my first submission here)

f=.;@|.@(]<;.2~'.?!'e.~])@,~&' '


f 'Hello friend. What are you doing? I bet it is something I want to do too!'

Perl, 27/25

#!perl -n
print reverse/ |[^.!?]*./g

Or from the command line:

$perl -nE'say reverse/ |[^.!?]*./g'
  • \$\begingroup\$ Nice! You can get the -5 bonus with perl -nE 'say reverse/ |[^.?!]*.\)?/g', bringing your total count to 23. \$\endgroup\$ – ThisSuitIsBlackNot May 15 '15 at 22:06

PHP, 60

echo join(' ',array_reverse(preg_split('/(?<=[?!.])/',$s)));
  • \$\begingroup\$ Can you use the regex [?!.]\K instead? \$\endgroup\$ – Martin Ender May 15 '15 at 13:20
  • \$\begingroup\$ Also doesn't this add additional spaces into the string unless you include the space in the pattern to split by? \$\endgroup\$ – Martin Ender May 15 '15 at 18:00
  • \$\begingroup\$ @MartinBüttner, no, I won't able to restore the proper sign when joining data back, so we need something which won't consume the character. \$\endgroup\$ – romaninsh May 19 '15 at 15:05

Bash + coreutils, 40 bytes

sed 's/\([?.!]\) */\1\n/g'|tac|tr \\n \ 

This reads from STDIN so input may me redirected in from a file, or simply piped in, e.g.:

$ printf 'Hello friend. What are you doing? I bet it is something I want to do too!' | sed 's/\([?.!]\) */\1\n/g'|tac|tr \\n \ 
I bet it is something I want to do too! What are you doing? Hello friend. 
  • \$\begingroup\$ Does this really work for parentheses in the sense, that (foo bar.) gets swapped as a unit? \$\endgroup\$ – Martin Ender May 15 '15 at 13:42
  • \$\begingroup\$ @MartinBüttner Looks like the question got edited, so I can no longer claim the bonus :( \$\endgroup\$ – Digital Trauma May 15 '15 at 15:33

Pip, 25 bytes


After appending a space to the input string, we find all indices of ., ?, and !, add 2, and use the ^@ split-at operator to break the string into sentences (each with a trailing space). Reverse the list, and it's auto-printed at the end of the program. Voilà!

Example showing the stages of the main computation with input A! B? C. D!:

              ^".?!"     ["." "?" "!"]
           a@*           [[7] [4] [1 10]]
        $AL              [7 4 1 10]
      2+                 [9 6 3 12]
   a^@                   ["A! " "B? " "C. " "D! "]
RV(                 )    ["D! " "C. " "B? " "A! "]

                         D! C. B? A! 
  • \$\begingroup\$ No you don't :) \$\endgroup\$ – Optimizer May 15 '15 at 11:48

Retina, 61 34 33 30 bytes

Credits to nutki for cutting this down by 24 bytes.

+`(#.*[.!?]) (.+)
$2 $1

Where <empty> stands for an empty line. This assumes that # is not part of the input, but if that's not legitimate, I could swap it out for any other character, including " (which I'd only need to handle for the bonus) or something unprintable. You can run the code like that in a single file if you use the -s flag, or you can put each line in a separate file and pass them all to Retina.

Reversing this with a single regex replacement is possible, but really cumbersome. Even with .NET balancing groups I needed something around 90 bytes, so instead I tried doing it in multiple steps.

In Retina, every pair of lines is one replacement stage, where the first line is the pattern and the second line is the replacement.


This stage simply prepares the string for further processing. It prepends a # as a marker. This marker indicates that everything in front of it has already been put in the right place, and everything after it still needs to be processed.

+`(#.*[.!?]) (.+)
$2 $1

This stage swaps the sentences, by repeatedly moving the last sentence in front of the # (which moves forwards through the string in the process). The +` instructs Retina to repeat this stage until the output stops changing. As an example, here is how the input foo. bar! blah? would be processed:

#foo. bar! blah?
blah? #foo. bar!
blah? bar! #foo.

And finally we simply remove the marker:

  • \$\begingroup\$ Why not just .+ => $0 # and repeated (.*?[.!?] )(.*#) => $2$1? \$\endgroup\$ – nutki May 15 '15 at 13:36
  • \$\begingroup\$ @nutki Oh, that's much nicer, thank you. :) \$\endgroup\$ – Martin Ender May 15 '15 at 13:37

Java, 113

s->{String t[]=s.split("(?<=[\\.?!]) "),u="";for(int i=t.length;i-->0;)u+=t[i]+" ";return u.replaceAll(".$","");}

JavaScript (ES6) 47 45

As it's stated, it's a simple regex exercise. In javascript:

// ES6 - FireFox only
F=t=>t.match(/\S[^.!?]+./g).reverse().join(' ')

// ES5 - so much longer
function G(t){return t.match(/\S[^.!?]+./g).reverse().join(' ')}


alert(G("Hello friend. What are you doing? I bet it is something I want to do too!"))

  • \$\begingroup\$ I was going to do javascript, but you beat me to it. \$\endgroup\$ – BobTheAwesome May 14 '15 at 22:04
  • \$\begingroup\$ This produces extra spaces before all but the last sentence (originally the first). Not sure if it is OK, as the task is not very well defined. \$\endgroup\$ – nutki May 15 '15 at 10:55
  • \$\begingroup\$ @nutki yes, I agree. Fixed \$\endgroup\$ – edc65 May 15 '15 at 11:16

Python 2, 62

Not going to improve for the bonus, as it's probably not worth the byte cost.

import re
print' '.join(re.split('(?<=[?!.]).',input())[::-1])
  • \$\begingroup\$ This does not qualify for the bonus. Look at the bonus example in the question \$\endgroup\$ – Optimizer May 15 '15 at 11:48
  • \$\begingroup\$ @Optimizer Look in the question history. At the time I updated my question to add the bonus, my output matched the example. There was nothing indicating that parenthesis could be outside of a period. \$\endgroup\$ – mbomb007 May 15 '15 at 14:06
  • \$\begingroup\$ I think the intention was this only from the beginning. A solid example came later though. Doesn't mean that you still get the bonus :) (I removed mine too) \$\endgroup\$ – Optimizer May 15 '15 at 14:09

Matlab (93 bytes)

y=[32 input('','s')];y=sortrows([cumsum(ismember(y,'?!.'),'reverse');y]',1)';disp(y(4:2:end))
  • This assumes the input doesn't contain leading or trailing spaces
  • Uses standard input and output
  • Tested in Matlab 2014b

Ruby 41

The other Ruby answers don't have enough WTF.

#!ruby -apF(?<=[.!?])\s
$_=$F.reverse*" "

This at least works in Ruby 2. If the a and F switch works in 1.8.7, I guess you could drop $_= to save three characters.

Reverses every line on stdin and print to stdout:

$ ruby foo.rb <<< "Hello. Hi. How are you? Good, you? fine, thanks."
fine, thanks. Good, you? How are you? Hi. Hello.
  • \$\begingroup\$ Could you please explain the answer. \$\endgroup\$ – Mohammad May 15 '15 at 19:27

Ruby, 48(42 without the puts) bytes


puts $*[0].scan(/\S[^.!?]+./).reverse.join(" ")


ruby reverse_sentence.rb 'Hello friend. What are you doing? I bet it is something I want to do too!'


I bet it is something I want to do too! What are you doing? Hello friend.

Criticism more than welcome.

  • 2
    \$\begingroup\$ Criticism: You spelled "sentence" incorrectly. \$\endgroup\$ – Alex A. May 15 '15 at 16:24
  • \$\begingroup\$ save 6 characters: .join(" ") => *" " \$\endgroup\$ – daniero May 15 '15 at 17:37
  • \$\begingroup\$ @AlexA. Best feedback ever! \$\endgroup\$ – DickieBoy May 17 '15 at 10:56
  • \$\begingroup\$ @daniero thanks, nice to know \$\endgroup\$ – DickieBoy May 17 '15 at 10:56

k, 31

{1_,/|(0,1+&x in"?!.")_x:" ",x}


k){1_,/|(0,1+&x in"?!.")_x:" ",x} "Hello friend. What are you doing? I bet it is something I want to do too!"
"I bet it is something I want to do too! What are you doing? Hello friend."

C# - LINQPAD - 93 - 5 = 88 bytes

void Main(){string.Join(" ",Regex.Split(Console.ReadLine(),"(?<=[.?!]) ").Reverse()).Dump();}

C# Console App 189 - 5 = 184 bytes

using System;using System.Linq;using System.Text.RegularExpressions;class P{static void Main(){Console.WriteLine(string.Join(" ",Regex.Split(Console.ReadLine(), "(?<=[.?!]) ").Reverse()));}}

regex shamelessly flogged from Alex A. :)

  • \$\begingroup\$ You can save 7 bytes by putting your application in namespace System then within that using Linq;usingText.RegularExpressions saving 2x system. \$\endgroup\$ – ldam May 15 '15 at 7:50
  • \$\begingroup\$ I don't think that this qualifies for the bonus. Look at the bonus example in the question \$\endgroup\$ – Optimizer May 15 '15 at 11:52

Clojure - 44 71 chars

(defn rs[s](reverse(re-seq #"\S.+?[.!?]"s)))

Improved and simplified RE, eliminated unnecessary whitespace.

Output is a sequence of the sentences in the original string, with the order of the sentences reversed:

Input: "Hello friend. What are you doing? I bet it is something I want to do too!" Output: ("I bet it is something I want to do too!" "What are you doing?" "Hello friend.")


Ruby, 47

$><<gets.strip.split(/(?<=[.?!]) /).reverse*' '

credits to Martin Büttner, for saving some characters.

  • 1
    \$\begingroup\$ You can read the input from STDIN with gets to save a byte, print it with $><< to save byte (no need for a space) and join the string with *'' to save two bytes. \$\endgroup\$ – Martin Ender May 15 '15 at 17:47
  • \$\begingroup\$ @MartinBüttner thanks for the suggestion, I wouldn't go with reading from the input from STDIN, though. Simply because there will be a trailing new line. \$\endgroup\$ – Mohammad May 15 '15 at 17:53
  • \$\begingroup\$ Actually, I think your code will currently result in a leading space. \$\endgroup\$ – Martin Ender May 15 '15 at 17:56
  • \$\begingroup\$ mmm, you're right. I'll see what should I do. \$\endgroup\$ – Mohammad May 15 '15 at 17:58

CJam, 21 bytes


This works by turning spaces after !s, .s and ?s into the number 1 (not the character 1 nor the character with code point 1, so the input can still contain those), splitting at 1's, reversing the order of the resulting chunks and joining by spaces.

Try it online in the CJam interpreter.

How it works

1                     e# B := 1
 q                    e# Q := input()
  {         }%        e# for each C in Q (map):
   1?                 e#   C := B ? C : 1
     _"!.?"-          e#   B := string(C).strip("!.?")
              1a/     e# Q := Q.split([1])
                 W%   e# Q := reverse(Q)
                   S* e# Q := Q.join(" ")
                      e# print(Q)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy