g | x | w | all
Bytes Lang Time Link
048AWK241203T184308Zxrs
015Pip211006T184434ZDLosc
055R240620T080609Zint 21h
3875Vyxal S211007T055941Zlyxal
072JavaScript Node.js230626T121309ZFhuvi
037Arturo230626T032434Zchunes
006Thunno 2 Ṡ230625T162234ZThe Thon
015GolfScript230214T161142Zemirps
8078><> Fish230126T114940Zmousetai
036Zsh211007T090511Zroblogic
nan220930T144241Zbigyihsu
510Nibbles220930T132923ZDominic
010Husk220930T120439ZNatte
006Stax220607T185052Zrecursiv
007Vyxal220530T045728Zemanresu
nanx8616 machine code190524T180504Z640KB
060Factor211007T053416Zchunes
068jq211006T205522ZSara J
110Rust190518T211437ZMaya
nan190528T135715ZLegenDUS
047brainfuck190529T080449ZDorian
105Pepe190517T100923Zu-ndefin
075Julia 1.0190528T230353Zgggg
053Ruby190521T034335Z83338
2164TeX190516T202452ZPhelype
062C gcc190517T073640Zjdt
126Brainf**k190520T020154Zcardboar
034sed190519T154033ZPJF
058Wolfram Language Mathematica190516T202144ZZaMoC
043Z80Golf190518T194817ZMaya
009Jelly190517T021817ZNick Ken
037PowerShell190518T054556Zmazzy
064sed190518T010819ZRich
073PHP190516T211946Z640KB
060Python 2190516T193427ZTFeld
017J190517T082327ZFrownyFr
050PowerShell190517T192127ZVeskah
090SNOBOL4 CSNOBOL4190517T183627ZGiuseppe
010Japt S190516T213901ZShaggy
007Japt S190517T172027ZOliver
126TSQL190517T152300ZBradC
054Haskell190517T140450Znimi
100Scala190517T131836ZSoapy
074Haskell190517T085647ZMax Yekh
109Java190516T215700ZBenjamin
071laskelH190517T101504ZCubic
179Whitespace190517T100854ZKevin Cr
050APL+WIN190517T070236ZGraham
076Icon190517T065709ZGalen Iv
090C# Visual C# Interactive Compiler190517T044734ZGymhgy
141Batch190517T002019ZNeil
008Stax190516T193925Zrecursiv
01005AB1E190516T193037ZMagic Oc
029Ruby with p190516T194103ZValue In
085Retina190516T201856ZFryAmThe
036JavaScript ES6190516T194159ZArnauld
024Perl 5 p190516T202931ZXcali
058Python 3190516T193126Zuser8568
020QuadR190516T194510ZAdá

AWK, 62 51 48 bytes

$0=gensub(/([^ ])([^ ]*)([^ ])/,"\\3\\2\\1","g")

Attempt This Online!

Thank you, wobtax!

{for(;i++<NF;)printf gensub(/^(.)(.*)(.)$/,"\\3\\2\\1 ",1,$i)}

Pip, 15 bytes

aR+XW{@a::a@va}

Takes the string as a command-line argument. Attempt This Online! Or, here's a 14-byte version in Pip Classic: Try it online!

Explanation

aR+XW{@a::a@va}
a                In the command-line argument,
 R               replace all matches of
  +XW            the regex `\w+`
     {        }  with the following callback function:
      @a          Take the first character of the matched string
          a@v     and its -1th (last) character
        ::        and swap them
             a    Return the modified string

R, 55 bytes

Reduce(paste,sub("(^.)(.*)(.$)","\\3\\2\\1",scan(,"")))

Attempt This Online!

Regex seems to be the shortest option despite the lengthy arguments in the sub.

(Golfed independently from this post.)

Vyxal S, 31 bitsv2, 3.875 bytes

⌈ƛḣǔp

Try it Online!

Ports Thunno 2.

Explained

⌈ƛḣǔp
⌈ƛ     # To each word after splitting on spaces
  ḣ    #   Push the first character, then the rest
   ǔ   #   Rotate right once 
    p  #   Prepend to the first character
# The S flag joins on spaces.

JavaScript (Node.js), 72 bytes

Solution without regex = two times longer!

s=>s.split` `.map(w=>w[w.length-1]+w.slice(1,-1)+(w[1]?w[0]:"")).join` `

Try it online!


More functional programming approach (81 bytes) :

s=>s.split` `.map(w=>[...w].map((c,i)=>i%(l=w.length-1)?c:w[l-i]).join``).join` `

Arturo, 37 bytes

$=>[replace&{/(\w)(\w*)(\w)}"$3$2$1"]

Try it!

Thunno 2 , 6 bytes

OıḢsṾƤ

Attempt This Online!

Explanation

OıḢsṾƤ  # Implicit input
O       # Split on spaces
 ı      # Map over the list:
  Ḣ     #  Extract the first character
   s    #  Swap so the rest is on top
    Ṿ   #  Rotate it right once
     Ƥ  #  Append the first character
        # Join the list by spaces
        # Implicit output

GolfScript, 19 15 bytes

-4 bytes by splitting on newlines

Input is taken seperated by newlines.

n/{[)\(]''+}%n*

Try it online!

Explanation

n/{[)\(]''+}%n* # whole program
n/              # split the <implicit> input by newlines
    {        }% # for each value in the split input
     [)  ]      # take the last item of the string
       \        # swap stack ; stack: <last letter> <word without last letter>
        (       # take the first item out of the string ; stack: <last letter> <word> <first letter>
          ''+    # concatenate into charcodes
              n* # join by newlines

><> (Fish), 80 78 bytes

3:i&1+:i:'!'(?v$4p30.
$&p4{g4:-1v?(0/p4
. 1ap31'v'/
|.!00+1p4$' ':/
"/"
o>:?!;

Saved 2 bytes trying to fix handling 1-letter words

Try it

enter image description here

Zsh, 36 bytes

for x;<<<$x[-1]${x:1:-1}$x[1]||<<<$x

Try it Online!

Lexurgy, 30 bytes

s:
[]$1 ([]*)$2 []$3=>$3 $2 $1

Nibbles, 5 bytes (10 nibbles)

:`(\@:`)\$

Word separator is newline character.

:`(\@:`)\$$ # (code with implicitly-added final $)
            # implicit map over lines of input:
:           # joined
 `(         # first character of
   \@       # reversed word
            # (and save leftover of reversed word in variable $)
            # with
     :      # joined
      `)    # all but first character of
        \$  # reversed leftover of reversed word
            # with
          $ # first character of leftover of reversed word
            # (so, first character of the original word)            

enter image description here

Husk, 10 bytes

wm§:→oṙ1hw

Try it online!

Explanation

wm§:→oṙ1hw
 m       w  map over each word
  §:        concatenate the
    →       last char
     o  h   and the rest
      ṙ1    rotated
w           join on spaces

Stax, 6 bytes

╡à⌂≤¬)

Run and debug it

Uses newline for the word delimiter

Vyxal, 7 bytes

⌈ƛḣǔp;Ṅ

Try it Online!

⌈     Ṅ # To the words split on spaces...
 ƛ   ;  # Over each
  ḣ     # Take the first character and the rest
   ǔ    # Rotate the rest
    p   # Append the first char

x86-16 machine code, IBM PC DOS, 39 38 32 bytes

$ xxd pwas.com
00000000: d1ee ac8a c8ac 8bd6 8bfe f2ae 574f 4f8a  ............WOO.
00000010: 25a4 4e88 245e 41e2 efb8 2409 aacd 21c3  %.N.$^A...$...!.

Unassembled:

D1 EE       SHR  SI, 1              ; DOS PSP (80H) for command line input 
AC          LODSB                   ; get input length, SI at beginning 
8A C8       MOV  CL, AL             ; input length in CX 
AC          LODSB                   ; load a space (word delimiter) into AL 
8B D6       MOV  DX, SI             ; save pointer for later output 
        WORD_LOOP: 
8B FE       MOV  DI, SI             ; start DI at beginning 
F2 AE       REPNZ SCASB             ; search for next word delimiter 
57          PUSH DI                 ; save beginning of next word 
4F          DEC  DI                 ; DI will now point to the byte after the space 
4F          DEC  DI                 ;  so it's necessary to back up two chars 
8A 25       MOV  AH, BYTE PTR[DI]   ; move last letter to AH 
A4          MOVSB                   ; move first letter to last position 
4E          DEC  SI                 ; offset MOVSB incrementing SI 
88 24       MOV  BYTE PTR[SI], AH   ; move last letter to first position 
5E          POP  SI                 ; SI to beginning of next word 
41          INC  CX                 ; offset LOOP decrementing CX 
E2 EF       LOOP WORD_LOOP          ; loop if not end of input string 
B8 0924     MOV  AX, 0924H          ; AH = 9, AL = '$' 
AA          STOSB                   ; write DOS string delimiter to end 
CD 21       INT  21H                ; write to console 
C3          RET                     ; return to DOS

Standalone PC DOS executable. Input via command line, output to console.

enter image description here

Factor, 60 bytes

[ " "split [ 1 cut 1 short cut* spin 3append ] map " "join ]

This doesn't run on TIO (Try it Online) because spin postdates build 1525, the one TIO uses. Here's a screenshot of running it in build 1889, the official 0.98 release:

A screenshot of running the above code in the Factor Listener (REPL)

Explanation

It's a quotation (anonymous function) that takes a string from the data stack as input and leaves a string on the data stack as output. Assuming "in a green meadow" is on top of the data stack when this quotation is called...

Snippet Comment Data stack (the bottom is the top)
" "split
Split a string into a sequence of space-delimited strings
{ "in" "a" "green" "meadow" }
[ ... ] map
Apply a quotation to each element of a sequence, collecting the results in a new sequence of the same length
Inside the quotation during the first iteration of map now...
"in"
1 cut
Split a string in two at index 1
"i"
"n"
1 short
The minimum of 1 and the length of the sequence on top of the stack — prevents cut* from trying to cut at an invalid index
"i"
"n"
1
cut*
Like cut, but works from the end of the sequence; not the start
"i"
""
"n"
spin
Swap the object on top of the data stack with the third object from the top of the data stack
"n"
""
"i"
3append
Append three sequences
"ni"
And so forth...
{ "ni" "a" "nreeg" "weadom" }
" "join
Join a sequence of strings into a single string separated by a space
"ni a nreeg weadom"

jq, 73 68 bytes

./" "|map((length<2//[./""|.[-1],.[1:-1][],.[0]]|add?)//.)|join(" ")

Try it online!

How?

  . / " "                             # Split on spaces
| map(                                # For each word...
    (
         length<2                     # If it's shorter than 2 letters, emit false
      // [   . / ""                   # Otherwise, emit the word's characters
           | .[-1], .[1:-1][], .[0]]  # ...in the order last, middle, first
      | add?                          # Then re-join the characters into an updated word. If we don't have a list of characters, (if the original was too short), emit nothing
    ) // .                            # If we didn't get a value, emit the word unchanged
  )
| join(" ")

Rust, 110 bytes

|a:&str|{for b in a.split(' '){let l=b.len()-1;if l>0{print!("{}{}",&b[l..],&b[1..l])}print!("{} ",&b[0..1])}}

Try it online!

A surprisingly long, but nicer solution that returns instead of printing (126 bytes):

|a:&str|->String{a.split(' ').flat_map(|b|{let mut q:Vec<_>=b.chars().collect();q.swap(0,b.len()-1);q.push(' ');q}).collect()}

Try it online!

If halting is not necessary:

Aheui (esotope), 174 bytes

삭붵뱷뛰빠쇡붷뼤쎄투@싼사쑫
ByLe쪼gen@처쇠모코커
DUST오멓@@@@푸셴쒼섣
@@@@쇡뽀@@@삳멓@샨@맣

Try it online! press 'start' butten in TIO again to halt manually.

If halting is necessary:

Aheui (esotope), 225 bytes

살뷕볙눠쀄삭붵뱷뛰빠쇡붷빠쎄투@싼사쑫
By@@@@@야빠속@@@수처쇠모오어
Legen@@먷초더헤셜썰뻐푸쉰썬@셛
DUST@@솩뽀사뫼섁쀠우삳멓산멓

Try it online!

In this version, following space after input is necessary. fixed. Now it is OK to not finish with space.

brainfuck, 71 67 49 47 bytes

+[-[+>>]>[<<.[-]<[<]>>[.>]<[<]>[.[>]].>>>]<+<,]

Try it online!

This code uses a few cheats, so i don't know if it is competing. The separator in the input is a 0x01. The input needs an extra trailing separator, otherwise the last word won't be printed.

code:

+[                  enter the loop / the first round only the last three commands of the main loop are interesting
  -[                if input is not 0x01
    +               restore character
    >>              go to exit if
  ]
  >[                else
    <<.[-]          print and delete last character
    <[<]>>[.>]      print all characters starting at the second
    <[<]>[.[>]]     print first character and go to end if word is longer than one character
    .               print null (space)
    >>>             leave a zero cell and go to exit else
  ]
  <+                set new else marker
  <                 go to new input location
  ,                 input next character
]

Pepe, 107 105 bytes

REEeREeeEeeeeerEEreREEEeREEEEEEeREEEErEEREEEEEEEreererEEEeererEEEerEEeERrEEEeerEEeerereeerEEEEeEEEReEeree

Try it online!

Explanation:

Notation on comments: command-explanation -> (stack) // explanation

REEe # input -> (R)
REeeEeeeee # push space to last -> (R) // this prevents an infinite loop

rEE # create loop labeled 0 and automatically push 0 
  re # pop 0 -> (r)
  REEEe # go to last item -> (R)
  REEEEEEe # ...then copy the char to other stack
  REEEE # go to first item -> (R)

  rEE # create loop labeled 32 // detect space
    REEEEEEE # move item to other stack (R)
  ree # do this while char != 32

  re # pop 32 -> (r)
  rEEEee # push item (dup to end) -> (r)
  re # ...then pop -> (r)
  rEEEe rEEeE # go to 2nd to last item -> (r)
  RrEEEee # push the item (R flag: dup to first) -> (r)
  rEEee # go to next -> (r) //
  re # ...then pop -> (r)
  reee rEEEEeEEE # out all as char then clear -> (r)
  ReEe # out 32 as char -> (R)
ree # do this while stack != 0

Julia 1.0, 75 bytes

x->join([(n=length(s);n<2 ? s : s[n]*s[2:n-1]*s[1]) for s in split(x)]," ")

Try it online!

Ruby, 53 bytes

gets.split(" ").map{|z|print z[-1]+z[1..-2]+z[0]," "}

I tried it without regex. The output prints each word on a new line. If that's against the rules, let me know and I'll fix it.

Ungolfed:

gets.split(" ").map {|z|
    print z[-1] + z[1..-2] + z[0], " "
}

TeX, 216 bytes (4 lines, 54 characters each)

Because it's not about the byte count, it's about the quality of the typeset output :-)

{\let~\catcode~`A13 \defA#1{~`#113\gdef}AGG#1{~`#1 13%
\global\let}GFF\elseGHH\fiAQQ{Q}AII{\ifxQ}AEE#1#2#3|{%
I#3#2#1FE{#1#2}#3|H}ADD#1#2|{I#1FE{}#1#2|H}ACC#1#2|{D%
#2Q|#1 }ABBH#1 {HI#1FC#1|BH}\gdef\S#1{\iftrueBH#1 Q }}

Try it Online! (Overleaf; not sure how it works)

Full test file:

{\let~\catcode~`A13 \defA#1{~`#113\gdef}AGG#1{~`#1 13%
\global\let}GFF\elseGHH\fiAQQ{Q}AII{\ifxQ}AEE#1#2#3|{%
I#3#2#1FE{#1#2}#3|H}ADD#1#2|{I#1FE{}#1#2|H}ACC#1#2|{D%
#2Q|#1 }ABBH#1 {HI#1FC#1|BH}\gdef\S#1{\iftrueBH#1 Q }}

\S{swap the a first and last letters of each word}

pwas eht a tirsf dna tasl setterl fo hace dorw

\S{SWAP THE A FIRST AND LAST LETTERS OF EACH WORD}

\bye

Output:

enter image description here


For LaTeX you just need the boilerplate:

\documentclass{article}
\begin{document}

{\let~\catcode~`A13 \defA#1{~`#113\gdef}AGG#1{~`#1 13%
\global\let}GFF\elseGHH\fiAQQ{Q}AII{\ifxQ}AEE#1#2#3|{%
I#3#2#1FE{#1#2}#3|H}ADD#1#2|{I#1FE{}#1#2|H}ACC#1#2|{D%
#2Q|#1 }ABBH#1 {HI#1FC#1|BH}\gdef\S#1{\iftrueBH#1 Q }}

\S{swap the a first and last letters of each word}

pwas eht a tirsf dna tasl setterl fo hace dorw

\S{SWAP THE A FIRST AND LAST LETTERS OF EACH WORD}

\end{document}

Explanation

TeX is a strange beast. Reading normal code and understanding it is a feat by itself. Understanding obfuscated TeX code goes a few steps further. I'll try to make this understandable for people who don't know TeX as well, so before we start here's a few concepts about TeX to make things easier to follow:

For (not so) absolute TeX beginners

(Sort of) ungolfing the code

Let's make that rectangle into something (arguably) easier to follow:

{
\let~\catcode
~`A13
\defA#1{~`#113\gdef}
AGG#1{~`#113\global\let}
GFF\else
GHH\fi
AQQ{Q}
AII{\ifxQ}
AEE#1#2#3|{I#3#2#1FE{#1#2}#3|H}
ADD#1#2#3|{I#2FE{#1}#2#3|H}
ACC#1#2|{D{}#2Q|#1 }
ABBH#1 {HI#1FC#1|BH}
\gdef\S#1{\iftrueBH#1 Q }
}

Explanation of each step

each line contains one single instruction. Let's go one by one, dissecting them:

{
First we start a group to keep some changes (namely catcode changes) local so that they don't mess up the input text.

\let~\catcode
Basically all TeX obfuscation codes start with this instruction. By default, both in plain TeX and LaTeX, the ~ character is the one active character which can be made into a macro for further use. And the best tool for weirdifying TeX code are catcode changes, so this is generally the best choice. Now instead of \catcode`A=13 we can write ~`A13 (the = is optional):

~`A13
Now the letter A is an active character, and we can define it to do something:

\defA#1{~`#113\gdef}
A is now a macro that takes one argument (which should be another character). First the catcode of the argument is changed to 13 to make it active: ~`#113 (replace the ~ by \catcode and add an = and you have: \catcode`#1=13). Finally it leaves a \gdef (global \def) in the input stream. In short, A makes another character active and start its definition. Let's try it:

AGG#1{~`#113\global\let}
AG first “activates” G and does \gdef, which followed by the next G starts the definition. The definition of G is very similar to that of A, except that instead of \gdef it does a \global\let (there isn't a \glet like the \gdef). In short, G activates a character and makes it be something else. Let's make shortcuts for two commands we'll use later:

GFF\else
GHH\fi
Now instead of \else and \fi we can simply use F and H. Much shorter :)

AQQ{Q}
Now we use A again to define another macro, Q. The above statement basically does (in a less obfuscated language) \def\Q{\Q}. This isn't a terribly interesting definition, but it has an interesting feature. Unless you do want to break some code, the only macro that expands to Q is Q itself, so it acts like a unique marker (it's called a quark). You can use the \ifx conditional to test if the argument of a macro is such quark with \ifx Q#1:

AII{\ifxQ}
so you can be pretty sure that you found such a marker. Notice that in this definition I removed the space between \ifx and Q. Usually this would lead to an error (note that the syntax highlight thinks that \ifxQ is one thing), but since now Q is catcode 13 it cannot form a control sequence. Be careful, however, not to expand this quark or you'll get stuck in an infinite loop because Q expands to Q which expands to Q which...

Now that the preliminaries are done, we can go to the proper algorithm to pwas eht setterl. Due to TeX's tokenization the algorithm has to be written backwards. This is because at the time you do a definition TeX will tokenize (assign catcodes) to the characters in the definition using the current settings so, for example, if I do:

\def\one{E}
\catcode`E=13\def E{1}
\one E

the output is E1, whereas if I change the order of the definitions:

\catcode`E=13\def E{1}
\def\one{E}
\one E

the output is 11. This is because in the first example the E in the definition was tokenized as a letter (catcode 11) before the catcode change, so it will always be a letter E. In the second example, however, E was first made active, and only then \one was defined, and now the definition contains the catcode 13 E which expands to 1.

I will, however, overlook this fact and reorder the definitions to have a logical (but not working) order. In the following paragraphs you can assume that the letters B, C, D, and E are active.

\gdef\S#1{\iftrueBH#1 Q }
(notice there was a small bug in the previous version, it did not contain the final space in the definition above. I only noticed it while writing this. Read on and you'll see why we need that one to properly terminate the macro.)
First we define the user-level macro, \S. This one shouldn't be an active character to have a friendly (?) syntax, so the macro for gwappins eht setterl is \S. The macro starts with an always-true conditional \iftrue (it will soon be clear why), and then calls the B macro followed by H (which we defined earlier to be \fi) to match the \iftrue. Then we leave the argument of the macro #1 followed by a space and by the quark Q. Suppose we use \S{hello world}, then the input stream should look like this: \iftrue BHhello world Q␣ (I replaced the last space by a so that the rendering of the site does not eat it, like I did in the previous version of the code). \iftrue is true, so it expands and we are left with BHhello world Q␣. TeX does not remove the \fi (H) after the conditional is evaluated, instead it leaves it there until the \fi is actually expanded. Now the B macro is expanded:

ABBH#1 {HI#1FC#1|BH}
B is a delimited macro whose parameter text is H#1␣, so the argument is whatever is between H and a space. Continuing the example above the input stream prior to the expansion of B is BHhello world Q␣. B is followed by H, as it should (otherwise TeX would raise an error), then the next space is between hello and world, so #1 is the word hello. And here we got to split the input text at the spaces. Yay :D The expansion of B removes everything up to the first space from the input stream and replaces by HI#1FC#1|BH with #1 being hello: HIhelloFChello|BHworld Q␣. Notice that there is a new BH later in the input stream, to do a tail recursion of B and process later words. After this word is processed B processes the next word until the word-to-be-processed is the quark Q. The last space after Q is needed because the delimited macro B requires one at the end of the argument. With the previous version (see edit history) the code would misbehave if you used \S{hello world}abc abc (the space between the abcs would vanish).

OK, back to the input stream: HIhelloFChello|BHworld Q␣. First there's the H (\fi) that completes the initial \iftrue. Now we have this (pseudocoded):

I
  hello
F
  Chello|B
H
world Q␣

The I...F...H think is actually a \ifx Q...\else...\fi structure. The \ifx test checks if the (first token of the) word grabbed is the Q quark. If it is there is nothing else to do and the execution terminates, otherwise what remains is: Chello|BHworld Q␣. Now C is expanded:

ACC#1#2|{D#2Q|#1 }
The first argument of C is undelimited, so unless braced it will be a single token, The second argument is delimited by |, so after the expansion of C (with #1=h and #2=ello) the input stream is: DelloQ|h BHworld Q␣. Notice that another | is put there, and the h of hello is put after that. Half the swapping is done; the first letter is at the end. In TeX it is easy to grab the first token of a token list. A simple macro \def\first#1#2|{#1} gets the first letter when you use \first hello|. The last one is a problem because TeX always grabs the “smallest, possibly empty” token list as argument, so we need a few work-arounds. Next item in the token list is D:

ADD#1#2|{I#1FE{}#1#2|H}
This D macro is one of the work-arounds and it's useful in the sole case where the word has a single letter. Suppose instead of hello we had x. In this case the input stream would be DQ|x, then D would expand (with #1=Q, and #2 empty) to: IQFE{}Q|Hx. This is similar to the I...F...H (\ifx Q...\else...\fi) block in B, which will see that the argument is the quark and will interrupt the execution leaving only x for typesetting. In other cases (returning to the hello example), D would expand (with #1=e and #2=lloQ) to: IeFE{}elloQ|Hh BHworld Q␣. Again, the I...F...H will check for Q but will fail and take the \else branch: E{}elloQ|Hh BHworld Q␣. Now the last piece of this thing, the E macro would expand:

AEE#1#2#3|{I#3#2#1FE{#1#2}#3|H}
The parameter text here is quite similar to C and D; the first and second arguments are undelimited, and the last one is delimited by |. The input stream looks like this: E{}elloQ|Hh BHworld Q␣, then E expands (with #1 empty, #2=e, and #3=lloQ): IlloQeFE{e}lloQ|HHh BHworld Q␣. Another I...F...H block checks for the quark (which sees l and returns false): E{e}lloQ|HHh BHworld Q␣. Now E expands again (with #1=e empty, #2=l, and #3=loQ): IloQleFE{el}loQ|HHHh BHworld Q␣. And again I...F...H. The macro does a few more iterations until the Q is finally found and the true branch is taken: E{el}loQ|HHHh BHworld Q␣ -> IoQlelFE{ell}oQ|HHHHh BHworld Q␣ -> E{ell}oQ|HHHHh BHworld Q␣-> IQoellFE{ello}Q|HHHHHh BHworld Q␣. Now the quark is found and the conditional expands to: oellHHHHh BHworld Q␣. Phew.

Oh, wait, what are these? NORMAL LETTERS? Oh, boy! The letters are finally found and TeX writes down oell, then a bunch of H (\fi) are found and expanded (to nothing) leaving the input stream with: oellh BHworld Q␣. Now the first word has the first and last letters swapped and what TeX finds next is the other B to repeat the whole process for the next word.

}
Finally we end the group started back there so that all local assignments are undone. The local assignments are the catcode changes of the letters A, B, C, ... which were made macros so that they return to their normal letter meaning and can be safely used in the text. And that's it. Now the \S macro defined back there will trigger the processing of the text as above.

One interesting thing about this code is that it is fully expandable. That is, you can safely use it in moving arguments without worrying that it will explode. You can even use the code to check if the last letter of a word is the same as the second (for whatever reason you would need that) in an \if test:

\if\S{here} true\else false\fi % prints true (plus junk, which you would need to handle)
\if\S{test} true\else false\fi % prints false

Sorry for the (probably far too) wordy explanation. I tried to make it as clear as possible for non TeXies as well :)

Summary for the impatient

The macro \S prepends the input with an active character B which grabs lists of tokens delimited by a final space and passes them to C. C takes the first token in that list and moves it to the end of the token list and expands D with what remains. D checks if “what remains” is empty, in which case a single-letter word was found, then do nothing; otherwise expands E. E loops through the token list until it finds the last letter in the word, when it is found it leaves that last letter, followed by the middle of the word, which is then followed by the first letter left at the end of the token stream by C.

C (gcc), 62 bytes

t;*s;f(int*i){for(s=i;*++i;i[1]>64||(t=*i,*i=*s,*s=t,s=i+2));}

I wanted to use a xor swap but that fails if a word is only one character long.

Try it online

Brainf**k, 126

>+[,[->>>+<+<+<]>----------[[-]<+>]>[[-]<<+>>]<<--[+<.<[[<]>>>[<.>>]<[<]>.<]>[>]>->>[.[-]<+>]<<<]>+[->>[-<<<+>>>]<+<]>[-<+>]<]

Try it online!

Could definitely be golfed further.

sed, 34 bytes

And presumably the pattern idea will work with most RE tools (and I do know there are differences between standard RE and extended RE).

s,\b\(\w\)\(\w*\)\(\w\)\b,\3\2\1,g

Try it online!

Wolfram Language (Mathematica), 58 bytes

StringReplace[#,a:u~~w:u..~~b:u:>b<>w<>a/.{u->Except@#2}]&

Try it online!

-22 bytes from @attinat

-12 bytes from @M.Stern

Z80Golf, 43 bytes

00000000: 2100 c0cd 0380 3822 5745 cd03 8038 09fe  !.....8"WE...8..
00000010: 2028 0570 4723 18f2 736b 707e 23a7 2803   (.pG#..skp~#.(.
00000020: ff18 f87a ff3e 20ff 18d6 76              ...z.> ...v

Try it online!

Corresponding assembly:

mainloop:
    ld hl, $c000
    call $8003
    jr c, hlt
    ld d, a
    ld b, l ; handle 1-character words
inputloop:
    call $8003
    jr c, endinput
    cp $20
    jr z, endinput
    ld (hl), b ; don't store the last character
    ld b, a
    inc hl
    jr inputloop
endinput:
    ld (hl), e ; always 0
    ld l, e
    ld (hl), b
outputloop:
    ld a, (hl)
    inc hl
    and a
    jr z, endoutput
    rst $38
    jr outputloop
endoutput:
    ld a, d
    rst $38
    ld a, $20
    rst $38
    jr mainloop
hlt:
    halt

Jelly, 9 bytes

ḲṪ;ṙ1$Ɗ€K

Try it online!

Explanation

ḲṪ;ṙ1$Ɗ€K | monadic link taking the string as input

Ḳ         | split at spaces
      Ɗ€  | for each word, do the following:
 Ṫ        | - pop the last letter
  ;ṙ1$    | - concatenate to the remaining letters rotated left once
        K | finally, join with spaces

PowerShell, 37 bytes

$args-replace'(\w)(\w*)(\w)','$3$2$1'

Try it online!

sed, 64 bytes

sed -E 's/\b([[:alpha:]])([[:alpha:]]*)([[:alpha:]])\b/\3\2\1/g'

PHP, 73 bytes

foreach(explode(' ',$argn)as$w){[$w[0],$w[-1]]=[$w[-1],$w[0]];echo"$w ";}

Try it online!

Using PHP 7.1's Square bracket syntax for array destructuring to swap values.

Ungolfed:

foreach( explode( ' ', $argn ) as $w ) {
  [ $w[0], $w[-1] ] = [ $w[-1], $w[0] ];
  echo $w, ' ';
}

Python 2, 67 66 64 61 60 bytes

lambda s:' '.join(w[1:][-1:]+w[1:-1]+w[0]for w in s.split())

Try it online!

-1 byte, thanks to squid

-1 byte, thanks to Erik the Outgolfer


Python 3, 63 61 58 57 bytes

print(*[w[1:][-1:]+w[1:-1]+w[0]for w in input().split()])

Try it online!

J, 23 17 bytes

({:,1|.}:)&.>&.;:

Try it online!

PowerShell, 50 bytes

-split"$args"|%{$_-replace'^(.)(.*)(.)$','$3$2$1'}

Try it online!

Uses regex to replace each word with a captured first and last letter surrounding the original core. If it's a single character, replace will find nothing and leave it alone.

SNOBOL4 (CSNOBOL4), 90 bytes

I	R =
	INPUT LEN(1) . L REM . M	:F(END)
	M ARB . M RPOS(1) REM . R
	OUTPUT =R M L	:(I)
END

Try it online!

Takes input separated by newlines; can be either uppercase or lowercase.

I R =					;* set R to empty string
  INPUT LEN(1) . L REM . M	:F(END)	;* take first character and set to L, and set the
					;* REMainder to M
  M ARB . M RPOS(1) REM . R		;* match an ARBitrary (possibly empty) run
					;* of characters to M up to but excluding the last character
					;* and save the last character to R
					;* if M is empty, (i.e., a one-letter word), then this fails 
					;* and nothing happens, so M remains empty and R remains empty
  OUTPUT =R M L	:(I)			;* output Right, Middle, Left, then goto I.
END

(previous version)

SNOBOL4 (CSNOBOL4), 92 bytes

I	R =M =
	INPUT LEN(1) . L ('' | ARB . M LEN(1) . R) RPOS(0)	:F(END)
	OUTPUT =R M L	:(I)
END

Try it online!

This is thematically the same, clearly, but suffers from using FAILURE as the termination status, preventing us from using FAILURE as a no-op as we do in the above. This then forces us to set M = as well as R =, which is 3 bytes.

Japt -S, 10 bytes

Convinced there has to be a shorter approach (and I was right) but this'll do for now.

¸ËhJDg)hDÌ

Try it

¸ËhJDg)hDÌ     :Implicit input of string
¸              :Split on spaces
 Ë             :Map each D
  h            :  Set the character at
   J           :    Index -1 to
    Dg         :    The first character in D
      )        :  End set
       h       :  Set the first character to
        DÌ     :    The last character in D
               :Implicit output, joined by spaces

Japt -S, 7 bytes

¸®ÎiZÅé

Try it

T-SQL, 126 bytes

SELECT STRING_AGG(STUFF(STUFF(value,1,1,RIGHT(value,1)),LEN(value),1,LEFT(value,1)),' ')
FROM STRING_SPLIT((SELECT*FROM t),' ')

Input is via a pre-existing table t with varchar field v, per our IO standards.

Reading from back to front, STRING_SPLIT breaks a string into individual rows via a delimiter, STUFF modifies the characters at the specified positions, then STRING_AGG mashes them back together again.

Haskell, 54 bytes

unwords.map f.words
f[a]=[a]
f(a:b)=last b:init b++[a]

Try it online!

Scala, 100 bytes

(b:String,c:String)=>b.split(c)map(f=>f.tail.lastOption++:(f.drop(1).dropRight(1)+f.head))mkString c

Haskell, 75 74 bytes

Fixed a bug pointed at by Cubic and also golfed down 1 byte.

f=unwords.map(#v).words
x#g=g(r$tail x)++[x!!0]
r=reverse
v[]=[]
v x=r$x#r

Try it online!

Java, 110 109 bytes

-1 bytes by using a newline for a delimeter

s->{int l;for(var i:s.split("\n"))System.out.println(i.charAt(l=i.length()-1)+i.substring(1,l)+i.charAt(0));}

TIO

laskelH, 71 bytes

h=reverse
s(x:y:o)=a:h(x:r)where(a:r)=h$y:o
s o=o
f=unwords.map s.words

Try it online!

Example in/output:

Swap the first and last letter in each word
This also works with single letter words like a

It is basically just a straight up implementation in which
I for words consisting of two or more letters cons the head
of the reversed tail on the reverse of the original head consed
on the reversed tail

Note that the rules say that we only have to support one kind
of separator - I am choosing spaces Technically it works with
other whitespace as well, but it will turn everything into spaces
in the end Line endings in this example usage are handled separately
to make the example output look nicer
pwaS eht tirsf dna tasl rettel ni hace dorw
shiT olsa sorkw hitw eingls rettel sordw eikl a

tI si yasicallb tusj a ttraighs pu nmplementatioi ni hhicw
I rof sordw gonsistinc fo owt ro eorm setterl sonc eht deah
fo eht deverser lait no eht eeversr fo eht lriginao deah donsec
no eht deverser lait

eotN that eht suler yas that ew ynlo eavh ot tuppors eno dink
fo reparatos - I ma ghoosinc spaces yechnicallT ti sorkw hitw
rtheo ehitespacw sa ,ellw tub ti lilw nurt gverythine onti spaces
ni eht dne einL sndinge ni shit example esagu era dandleh yeparatels
ot eakm eht example tutpuo kool ricen
```

Whitespace, 179 bytes

[N
S S S N
_Create_Label_OUTER_LOOP][S S S N
_Push_n=0][N
S S T   N
_Create_Label_INNER_LOOP][S N
S _Duplicate_n][S N
S _Duplicate_n][S N
S _Duplicate_n][T   N
T   S _Read_STDIN_as_character][T   T   T   _Retrieve_input][S S S T    S T T   N
_Push_11][T S S T   _Subtract_t=input-11][N
T   T   S S N
_If_t<0_jump_to_Label_PRINT][S S S T    N
_Push_1][T  S S S _Add_n=n+1][N
S N
T   N
_Jump_to_Label_INNER_LOOP][N
S S S S N
_Create_Label_PRINT][S S S T    N
_Push_1][T  S S T   _Subtract_n=n-1][S N
S _Duplicate_n][S N
S _Duplicate_n][N
T   S N
_If_n==0_jump_to_Label_PRINT_TRAILING][T    T   T   _Retrieve][T    N
S S _Print_as_character][S S S N
_Push_s=0][N
S S S T N
_Create_Label_PRINT_LOOP][S S S T   N
_Push_1][T  S S S _Add_s=s+1][S N
S _Duplicate_s][S T S S T   S N
_Copy_0-based_2nd_n][T  S S T   _Subtract_i=s-n][N
T   S N
_If_0_Jump_to_Label_PRINT_TRAILING][S N
S _Duplicate_s][T   T   T   _Retrieve][T    N
S S _Print_as_character][N
S T S T N
_Jump_to_Label_PRINT_LOOP][N
S S N
_Create_Label_PRINT_TRAILING][S S S N
_Push_0][T  T   T   _Retrieve][T    N
S S _Print_as_character][S S S T    S S T   N
_Push_9_tab][T  N
S S _Print_as_character][N
S N
S N
_Jump_to_Label_OUTER_LOOP]

Letters S (space), T (tab), and N (new-line) added as highlighting only.
[..._some_action] added as explanation only.

Tab as delimiter. Input should contain a trailing newline (or tab), otherwise the program doesn't know when to stop, since taking input in Whitespace can only be done one character at a time.

Try it online (with raw spaces, tabs, and new-lines only).

Explanation in pseudo-code:

Whitespace only has a stack and a heap, where the heap is a map with a key and value (both integers). Inputs can only be read one integer or character at a time, which are always placed in the heap as integers, and can then be received and pushed to the stack with their defined heap-addresses (map-keys). In my approach I store the entire word at the heap-addresses (map-keys) \$[0, ..., \text{word_length}]\$, and then retrieve the characters to print one by one in the order we'd want after a tab (or newline) is encountered as delimiter.

Start OUTER_LOOP:
  Integer n = 0
  Start INNER_LOOP:
    Character c = STDIN as character, saved at heap-address n
    If(c == '\t' OR c == '\n'):
      Jump to PRINT
    n = n + 1
    Go to next iteration of INNER_LOOP

  PRINT:
    n = n - 1
    If(n == 0): (this means it was a single-letter word)
      Jump to PRINT_TRAILING
    Character c = get character from heap-address n
    Print c as character
    Integer s = 0

    Start PRINT_LOOP:
      s = s + 1
      If(s - n == 0):
        Jump to PRINT_TRAILING
      Character c = get character from heap-address s
      Print c as character
      Go to next iteration of PRINT_LOOP

    PRINT_TRAILING:
      Character c = get character from heap-address 0
      Print c as character
      Print '\t'
      Go to next iteration of OUTER_LOOP

The program terminates with an error when it tries to read a character when none is given in TIO (or it hangs waiting for an input in some Whitespace compilers like vii5ard).

APL+WIN, 50 bytes

(∊¯1↑¨s),¨1↓¨(¯1↓¨s),¨↑¨s←((+\s=' ')⊂s←' ',⎕)~¨' '

Prompts for string and uses space as the delimiter.

Try it online! Courtesy of Dyalog Classic

Icon, 76 bytes

link segment
procedure f(s)
w:=!seglist(s,' ')&w[1]:=:w[-1]&writes(w)&\x
end

Try it online!

C# (Visual C# Interactive Compiler), 90 bytes

n=>n.Split().Any(x=>WriteLine(x.Length<2?x:x.Last()+x.Substring(1,x.Length-2)+x[0])is int)

Uses newline as delimiter, though really any whitespace can be used.

Try it online!

Batch, 141 bytes

@set t=
@for %%w in (%*)do @call:c %%w
@echo%t%
@exit/b
:c
@set s=%1
@if not %s%==%s:~,1% set s=%s:~-1%%s:~1,-1%%s:~,1%
@set t=%t% %s%

Takes input as command-line parameters. String manipulation is dire in Batch at best, and having to special-case single-letter words doesn't help.

Stax, 8 bytes

Σq╞♪áZN¢

Run and debug it

Uses newlines as word separators.

05AB1E, 10 bytes

#vyRćsRćðJ

Try it online!


-3 Thanks to @Kevin Cruijssen.

#           | Split into words.
 vy         | For each word...
   RćsRć    | Reverse, split head, swap, reverse, split tail
        ðJ  | Join by spaces.

Ruby with -p, 42 41 29 bytes

gsub /(\w)(\w*)(\w)/,'\3\2\1'

Try it online!

Retina, 8 5 bytes

,V,,`

Try it online!

Saved 3 bytes thanks to Kevin Cruijssen!

Uses a newline as the separator. We make use of Retina's reverse stage and some limits. The first limit is which matches to apply the reversal to, so we pick all of them with ,. Then we want the first and last letter of each match to be swapped, so we take each letter in the range ,, which translates to a range from the beginning to the end with step size zero.

JavaScript (ES6),  39  36 bytes

Saved 3 bytes thanks to @FryAmTheEggman

Uses a linefeed as separator.

s=>s.replace(/(.)(.*)(.)/g,'$3$2$1')

Try it online!

Perl 5 -p, 24 bytes

s/(\w)(\w*)(\w)/$3$2$1/g

Try it online!

Python 3, 72 58 bytes

print(*[x[-1]+x[1:-1]+x[:x>x[0]]for x in input().split()])

Try it online!

QuadR, 20 bytes

(\w)(\w*)(\w)
\3\2\1

Simply make three capturing groups consisting of 1, 0-or-more, and 1 word-characters, then reverses their order.

Try it online!