In chat, we are often fast-typers and don't really look at the order of letters before posting a message. Since we are lazy, we need a program that automatically swaps the last two letters in our words, but since we don't want to respond too late, the code must be short.
Your task, if you wish to accept it, is to write a program that flips the last two letters of each word in a given string (so the word Thansk turns into Thanks). A word is a sequence of two or more letters in the English alphabet delimited by a single space.
The string / list of characters you receive as input is guaranteed to only contain alphabetic characters and spaces (ASCII [97 - 122], [65 - 90] and 32).
You can take input and provide output through any standard method, in any programming language, while taking note that these loopholes are forbidden by default.
The output may have one trailing space and / or one trailing newline.
The input will always contain words only (and the corresponding whitespace) and will consist of at least one word.
This is code-golf, so the shortest submission (scored in bytes), in each language wins!
Test cases
Note that the strings are surrounded with quotes for readability.
Input -> Output "Thansk" -> "Thanks" "Youer welcoem" -> "Youre welcome" "This is an apple" -> "Thsi si na appel" "Flippign Lettesr Aroudn" -> "Flipping Letters Around" "tHe oDd chALlEneg wiht swappde lettesR" -> "teH odD chALlEnge with swapped letteRs"
Or, for test suite convenience, here are the inputs and their corresponding outputs separately:
Thansk Youer welcoem This is an apple Flippign Lettesr Aroudn tHe oDd chALlEneg wiht swappde lettesR
Thanks Youre welcome Thsi si na appel Flipping Letters Around teH odD chALlEnge with swapped letteRs
Thanks to DJMcMayhem for the title. This was originally a CMC.
-
\$\begingroup\$ May we output an array of words? \$\endgroup\$Shaggy– Shaggy2017年12月27日 22:03:51 +00:00Commented Dec 27, 2017 at 22:03
-
\$\begingroup\$ @Shaggy No, the output must be a string (or a list of characters by default) \$\endgroup\$Mr. Xcoder– Mr. Xcoder2017年12月27日 22:04:47 +00:00Commented Dec 27, 2017 at 22:04
-
\$\begingroup\$ May we request a trailing space on each input? \$\endgroup\$FlipTack– FlipTack2017年12月29日 12:23:21 +00:00Commented Dec 29, 2017 at 12:23
-
1\$\begingroup\$ Whta shoudl eb doen wiht oen lettre worsd liek "a"? \$\endgroup\$Fabian Röling– Fabian Röling2017年12月29日 14:08:09 +00:00Commented Dec 29, 2017 at 14:08
-
2\$\begingroup\$ @Fabian A word is a sequence of two or more letters \$\endgroup\$Mr. Xcoder– Mr. Xcoder2017年12月29日 14:12:13 +00:00Commented Dec 29, 2017 at 14:12
48 Answers 48
K (oK), (削除) 23 (削除ここまで) 22 bytes
" "/{x@prm[!#x]1}'" "\
Example:
" "/{x@prm[!#x]1}'" "\"Hello World"
"Helol Wordl"
Explanation:
Port of FrownyFrog's solution to save 1 byte.
I'll come back to this.
" "/{prm[x]1}'" "\ / the solution
" "\ / split input on " "
{ }' / apply lambda to each
prm[x] / permute input x
1 / and take the 2nd result
" "/ / join with " "
Previous solution:
" "/-2{(x_y),|x#y}'" "\23 bytes
-
\$\begingroup\$ This is 11 bytes \$\endgroup\$Daniel W.– Daniel W.2017年12月28日 12:50:45 +00:00Commented Dec 28, 2017 at 12:50
-
2\$\begingroup\$ @DanFromGermany No, 05AB1E has a code page in which this can be represented as 8 bytes. \$\endgroup\$Erik the Outgolfer– Erik the Outgolfer2017年12月28日 12:51:24 +00:00Commented Dec 28, 2017 at 12:51
-
\$\begingroup\$ Can you run the program represented in 8 bytes? \$\endgroup\$Daniel W.– Daniel W.2017年12月28日 13:06:06 +00:00Commented Dec 28, 2017 at 13:06
-
\$\begingroup\$ @DanFromGermany Yes, the 05AB1E interpreter can run this program from a file in the 05AB1E encoding. \$\endgroup\$Erik the Outgolfer– Erik the Outgolfer2017年12月28日 13:09:19 +00:00Commented Dec 28, 2017 at 13:09
-
1\$\begingroup\$ @MagicOctopusUrn It's not a list though, it's after
`. \$\endgroup\$Erik the Outgolfer– Erik the Outgolfer2018年02月02日 14:58:41 +00:00Commented Feb 2, 2018 at 14:58
Ly, 30 bytes
i00I[rpr' =[ppf' 0]p0I]pfrp[o]
This one reads all the input into the stack, then copies characters one at a time to the other end of the stack (with a null separator between the original and the "fixed" codepoints). Anytime a space it found, it reverse the position of the previous two codepoints.
When the loop hits the null separator it end, then the just prints the stack.
i00I[rpr' =[ppf' 0]p0I]pfrp[o]
i0 # Read all the input, then push a null
0I # Copy the bottom of the stack to the top
[ ]p # Loop until the null reaches the bottom of the stack
rpr # Reverse, pop, reverse (delete bottom of the stack)
0I # Copy the bottom of the stack to the top
' = # Is the codepoint " "?
[p 0]p # If-then, runs if codepoint is " "
pf' # Delete " ", flip two entries, add " " back
f # End of input, flip the last two codepoints
rp # Reverse stack, delete null
[o] # Print the stack as characters
-
\$\begingroup\$ 5 bytes \$\endgroup\$Aaroneous Miller– Aaroneous Miller2021年07月18日 15:04:50 +00:00Commented Jul 18, 2021 at 15:04
Lexurgy, 24 bytes
This kind of challenge is one of the canonical reasons for captures in Lexurgy to exist (for things like metathesis and reduplication).
Capture 2 of any character, and swap their order when they are at the end of a "word".
a:
[]1ドル []2ドル=>2ドル 1ドル/_ $
BQN, 17 characters
∾(+`«∘≠⟜' ')⌽ ̈∘⊔⊢
Explanation
The function consists of a two 2 and a 3-train. If we were to write it out with the argument x where necessary and function composition removed, we'd have:
{∾ ⌽ ̈ (+` « ' '≠x) ⊔ x}
Below, I've tried to sketch what happens and I use the golfed code again:
⊢ # For the left argument of group (⊔) we use the identity
# function, i.e. it receives the string argument.
( ≠⟜' ') # For the right argument we start by mapping the string
# using the predicate ≠⟜' ', so "The bomb" becomes 1‿1‿1‿0‿1‿1‿1‿1.
« # Shift left by 1 which shifts in 0, so we get 1‿1‿0‿1‿1‿1‿1‿0.
+` # Scan using + left to right, so we get 1‿2‿2‿3‿4‿5‿6‿6.
# By shifting the boolean array to the left, we have
# ensured that the position before a space in the original
# argument gets the same number as its predecessor in the
# scan result!
⊔ # Group the original argument into "buckets" designated by the
# integer list we just computed for the left argument which
# gives us: ⟨ "", "T", "he", " ", "b", "o", "mb" ⟩
⌽ ̈ # Reverse every string: ⟨ "", "T", "eh", " ", "b", "o", "bm" ⟩
∾ # Concatenate: "Teh bobm"
∾(+`«∘≠⟜' ')⌽ ̈∘⊔⊢ # The entire thing.
SNOBOL4 (CSNOBOL4), (削除) 136 (削除ここまで) 119 bytes
I =INPUT
B I SPAN(&LCASE &UCASE) . Y ARBNO(' ') =:F(O)
Y RPOS(2) REM . Z =REVERSE(Z)
O =O Y ' ' :(B)
O OUTPUT =O
END
Prints with a trailing space. (削除) You know you've done something wrong when a language is a backronym for StriNg Oriented and symBOlic Language and your code is longer than Brain-Flak :( (削除ここまで) now it's slightly better.
Line B takes I and replaces (alphabetic characters saved as Y)(some number of spaces) with the empty string.
The following line extracts the last 2 characters of Y as Z and replaces them as Z reversed, then the next line concatenates O, Y, and a single space character.
Finally, it prints when I no longer matches the required pattern in line B.
Standard ML (MLton), (削除) 92 (削除ここまで) 77 bytes
implode o foldr(fn(a,b:: #" "::r)=>b::a:: #" "::r|(a,r)=>a::r)[#" "]o explode
Try it online! Based on xnor's Haskell solution.
Previous 92 byte version
fun f(a::b:: #" "::r)=b::a:: #" "::f r|f(x::r)=x::f r|f r=r
fun$s=implode(f(explode(s^" ")))
Try it online! Example usage: $ "Flippign Lettesr Aroudn" yields "Flipping Letters Around ".
Ungolfed
fun f (a :: b :: #" " :: r) = b :: a :: #" " :: f r
| f (x :: r) = x :: f r
| f r = r
fun g s = implode (f (explode (s ^ " ")))
Wolfram Language (Mathematica), 72 bytes
x""<>(Characters[StringSplit@x][[;;,#]]&/@{;;-3,-1,-2})~Riffle~" "
Another approach using manipulation of character list and take parts instead of string regex.
The two Unicode characters are \[Function] and \[Transpose] in private use area of Mathematica, take 3 bytes each.
74 bytes
Excel VBA, 78 Bytes
Anonymous VBE immediate window that takes input from range A1 and outputs to the VBE immediate window.
For Each s in Split([A1]):l=Len(s):?Left(s,l-2)Right(s,1)Mid(s,l-1,1)" ";:Next
Ruby, 53 bytes
$*.each{|x|print x[0,x.length-2]+x[-2,2].reverse," "}
The program takes input through command line arguments (formatted as a regular sentence, without quotes).
$* is a shorthand for ARGV, therefore i can iterate over each of the words, already in an array.
Only thing that bugs me is that awful x.length-2 snippet. I would prefer to use x.last(-2), but i believe that is only in RoR.
Called like:
ruby file.rb Helol Wordl
So that each word becomes a parameter. (Not wrapped in quotes)
-
\$\begingroup\$ Doesn’t return the correct results for me. The letters aren’t swapped on all the words. \$\endgroup\$Mr. Xcoder– Mr. Xcoder2017年12月29日 19:31:01 +00:00Commented Dec 29, 2017 at 19:31
-
\$\begingroup\$ @Mr.Xcoder It is because TIO passes the argument in quotes :) Add a argument for each word, and it works \$\endgroup\$Håvard Nygård– Håvard Nygård2017年12月29日 19:42:08 +00:00Commented Dec 29, 2017 at 19:42
-
\$\begingroup\$ This works, in practice, atleast on windows you can pass arguments without quotes, hence you can type it as if you typed a regular sentence \$\endgroup\$Håvard Nygård– Håvard Nygård2017年12月29日 19:44:52 +00:00Commented Dec 29, 2017 at 19:44
Clojure, (削除) 122 (削除ここまで) 117 bytes
-5 bytes by shortcutting the indices of the characters to swap
(fn[p](map #(let[l(count %)v(vec %)y(dec l)z(- l 2)](apply str(assoc v y(v z)z(v y))))(clojure.string/split p #" ")))
It's a shame that most of Clojure's String function are tucked away inside of Clojure.string, and that there are no good ways of manipulating the characters of Strings directly. clojure.string/split is atrociously long, and the conversion to-and-from vectors added quite a lot. I might be able to shave off a couple bytes by shortcutting the trailing indices, but this is the only decent algorithm I could think of.
(defn flip-last [phrase]
(let [words (clojure.string/split phrase #" ")]
; For each word...
(map #(let [len (count %)
; Need to turn the string into a vector so we can manipulate it using indices
vec-word (vec %)]
; ... then turn the vector of characters back into a String.
(apply str
; Associate the element at the second last index with the element at the last index,
; and vice-versa...
(assoc vec-word (dec len) (vec-word (- len 2))
(- len 2) (vec-word (dec len)))))
words)))
QuadR, 8 bytes
..\b
⌽⍵M
..\b any two characters followed by a word boundary
gets replaced with
⌽⍵M the reverse of the Match
Equivalent to the following 18-byte Dyalog APL function:
'..\b'⎕R{⌽⍵.Match}
Japt -S, (削除) 7 (削除ここまで) 6 bytes
A port of Jonathan's Jelly solution.
̧Ëá ÅÎ
̧Ëá ÅÎ :Implicit input of string
̧ :Split on spaces
Ë :Map
á : Permutations
Å : Slice off the first element
Î : Get the first element
:Implicit output joined with spaces
PHP4 (48 chars)
Given $argv[1] as a command line argument :
echo preg_replace('#(.)(.)\b#','2ドル1ドル',$argv[1]);
PHP7.4 (48 chars)
The function $f is inverting the last two chars of every word :
$f=fn($s)=>preg_replace('#(.)(.)\b#','2ドル1ドル',$s);
Try it Online - Usage :
echo $f('Flippign Lettesr Aroudn');
Both versions are using 🐘's PCRE Text Processing Functions.
Info: Support for PHP4 has been discontinued since 2008 but same code still works in PHP8.1.
Mathematica (58 chars)
f=StringReplace[#,RegularExpression["(.)(.)\\b"]:>"2ドル1ドル"]&
Factor, 50 bytes
[ " "split [ 2 cut* reverse append ] map " "join ]
Factor's regular expressions don't support backreferences for philosophical reasons, so here's (possibly) the next best thing. It splits the input on spaces, applies a quotation to each word, and joins them with a space into a single string. Here's how the mapping quotation works:
! "Flipping"
2 cut* ! "Flippi" "ng"
reverse ! "Flippi" "gn"
append ! "Flippign"
AWK, 34 bytes
0ドル=gensub(/(.)(.)\>/,"\2円\1円","g")
Or, before I figured out the regex trick, at 64 bytes:
{for(;$++i;)printf substr($i,1,l=split($i,a,X)-2)a[l+++2]a[l]FS}