# Swap letter and digit runs

Given an input string containing only alphanumeric ASCII characters and starting with a letter, swap each letter run with the digit run which follows.

A run is a sequence of consecutive letters or digits. Note that in the case where the input string ends with a run of letters, this run is left untouched.

Walk-through example

For instance, given the input string uV5Pt3I0:

1. Separate runs of letters and runs of digits: uV 5 Pt 3 I 0
2. Identify pairs of runs: (uV 5) (Pt 3) (I 0)
3. Swap pairs of runs: (5 uV) (3 Pt) (0 I)
4. Concatenate: 5uV3Pt0I

Examples

uV5Pt3I0 -> 5uV3Pt0I
J0i0m8 -> 0J0i8m
abc256 -> 256abc
Hennebont56Fr -> 56HennebontFr
Em5sA55Ve777Rien -> 5Em55sA777VeRien
nOoP -> nOoP


This is so the shortest answer in bytes wins. Explanations are encouraged.

# Retina, 15 bytes

(\D+)(\d+)
$2$1


This replaces the regex (\D+)(\d+) with $2$1. Let's break that down if you don't know what that means.

The \D means 'match anything that isn't a number'. \d means 'match everything that is a number'. The + sign means 'match this at least once but try to match it as many times as possible'. The brackets define a group. The first group is (\D+) and the second is (\d+)

In the second line we say that we want to put whatever was matched by the second group, followed by whatever was matched by the first group. This effectively swaps the letter and digit runs.

Try it online!

# Jelly, 9 bytes

~ṠŒg⁸ṁṭ2/


Try it online!

### How it works

~ṠŒg⁸ṁṭ2/  Main link. Argument: s (string)

~          Apply bitwise NOT.
Bitwise operators attempt to cast to int, so if c is a digit, this
yields ~int(c), a negative number.
If c cannot be cast to int, ~ will yield 0.
Ṡ         Take the sign.
We've now mapped digits to -1, non-digits to 0.
Œg       Group consecutive equal elements.
⁸ṁ     Mold s as the result, grouping run of digits and runs of non-digits.
2/  Reduce all pairs of runs by...
ṭ        tack, appending the first run of the pair to the second run.


Thanks to @Laikoni for shaving off 2 bytes

f""=""
f s|(a,(b,y))<-span(<':')<$>span(>'9')s=b++a++f y  Try it online! Ungolfed: f "" = "" f string | (letters, afterLetters) <- span (> '9') string , (numbers, afterNumbers) <- span (< ':') afterLetters = numbers ++ letters ++ f afterNumbers  • Save two bytes with (a,(b,y))<-span(<':')<$>span(>'9')s. Jul 5 '17 at 5:38
• Save even more with (a,(b,y):_)<-lex<$>span(>'9')s: Try it online! Jul 5 '17 at 6:03 • @Laikoni: Thanks for the tip! I'm not really clear on how lex works, so I'm gonna refrain from including that for now. In any case, good to know that there's something like that in Prelude Jul 5 '17 at 6:11 # JavaScript (ES6), 34 bytes s=>s.replace(/(\D+)(\d+)/g,"$2$1")  ## Try it o.innerText=(f= s=>s.replace(/(\D+)(\d+)/g,"$2$1") )(i.value="uV5Pt3I0");oninput=_=>o.innerText=f(i.value) <input id=i><pre id=o> # Pyth, 15 bytes ss_Mc:z"(\d+)"3 2  Explanation  :z"(\d+)"3 # Split the input z onto matches of numbers (\d+) c 2 # Split the resulting list in pieces of length 2 _M # Reverse each pair ss # Concatenate  # Python 2, 49 bytes Every non-regex solution I tried was longer. :P lambda s:re.sub('(\D+)(\d+)',r'\2\1',s) import re  Try it online! # Japt (v2.0a0), 16 bytes q/(\d+/ ò mw c q  Test it online! Note: this is an unstable alpha, so if this link breaks, you can use a slightly longer version in v1.4.4: Test it online! ### Explanation q/(\d+/ ò mw c q : Implicit input "uV5Pt3I0" q : Split input on /(\d+/ : runs of digits, keeping each run. (This compiles to the regex /(\d+)/g) : This gives ["uV","5","Pt","3","I","0",""] ò : Take every pair of items. [["uV","5"],["Pt","3"],["I","0"],[""]] m : Map each pair by w : reversing. [["5","uV"],["3","Pt"],["0","I"],[""]] c : Flatten into one array. ["5","uV","3","Pt","0","I",""] q : Join into a single string. "5uV3Pt0I" : Implicit: output result of last expression  • Was trying to figure out if there was a way to do it with ò. Jul 4 '17 at 19:08 # CJam, 3230 28 bytes q{i_64>X\:X^{])[}&c}/]]2/Wf%  CJam has no regex and no "split into digits and letters" or whatnot, so this was kind of painful. Try it online! ### Explanation q e# Read the input. { e# Do the following for every char c: i e# Get c's codepoint. 64> e# Check if it's greater than 64 (i.e. if it's a letter), pushing 1 or 0. X e# Push X (variable predefined to 1). \:X e# Store whether c was a letter or digit into X. ^{ e# If (old X) XOR (new X) is 1: ] e# Close the current array. ) e# Pull out its last character. [ e# Open a new array. }& e# (end if) c e# Turn the codepoint back into a character. This also shoves it into the new array, e# in case one was opened. }/ e# (end for) ] e# Close the final array, since it hasn't been closed yet. ] e# Wrap the whole stack into an array. 2/ e# Split elements into groups of 2. Wf% e# Reverse each group. e# Implicitly flatten and print.  # Gema, 11 characters <L><D>=$2$1  Sample run: bash-4.4$ gema '<L><D>=$2$1' <<< 'Em5sA55Ve777Rien'
5Em55sA777VeRien

• So...short. I mean, it's not a golfing language and just 11? Wow. Jul 5 '17 at 8:02
• Yeah, but only for tasks which not require touching the same input twice. Then it becomes nightmare. ☹ Jul 5 '17 at 8:27
• Found Gema through one of your other posts... cool language. Just how obscure would you say Gema is? Feb 2 '18 at 0:50
• @Jonah, I would say its only obscure part is the domain. Though that is partially because the feature is underdocumented. Otherwise the language is a collection of great but painfully limited features. (For example the recognizers rocks, but they would be much powerful if could be combined like the regular expression character classes.) Feb 2 '18 at 9:10
• how popular was gema in the 90s? and does it have any modern counterparts / competitors? do you use it for work or just found it for fun? Feb 2 '18 at 12:44

# Java 8, 38 bytes

s->s.replaceAll("(\\D+)(\\d+)","$2$1")


Not much to explain. Uses the same method as @Okx's Retina answer, which can't be any shorter in Java.

Try it here.

# Sed, 29 bytes

s/([^0-9]+)([0-9]+)/\2\1/g


Run with -r.

Uses capture groups and replaces them in the opposite order.

• You can shorten [A-Za-z] to [^0-9]. However, you have to count the flag as part of your code. Jul 4 '17 at 20:45
• How much does the flag count as? Jul 4 '17 at 20:47
• The difference between sed <command> and sed -r <command>, so three bytes. Jul 4 '17 at 20:50
• @Dennis, it's the difference between sed -f filename and sed -rf filename (or between sed -e 'command' and sed -re 'command'): a single byte. Jul 5 '17 at 12:15
• I missed the key phrase ("starting with a letter") in the question, so had s/([a-z]+)([0-9]+)|([0-9]+)([a-z]+)/\2\1\4\3/gi at 48 bytes. Otherwise, much the same. Jul 5 '17 at 12:17

# Jelly, 12 bytes

e€ØDŒg⁸ṁs2Ṛ€


Try it online!

Explanation:

e€ØDŒg⁸ṁs2Ṛ€ Accepts a string
e€ØD         Check if each char is in ['0'..'9']
Œg       Split runs of 0s and 1s (respectively letter and digit runs)
⁸ṁ     Replace with input, keeping the split
s2   Get pairs of runs, last left alone if letter run
Ṛ€ Swap each pair

• Can you add the explanation?
– Jim
Jul 4 '17 at 18:34
• @Jim Added explanaion. Jul 5 '17 at 7:55

# PHP, no regex, 73 bytes

for(;a&$c=$argn[$i++];$p=$c)$c<A?print$c:$s=($p<A?!print$s:$s).$c;echo$s;  Run as pipe with -nR or test it online. breakdown for(;a&$c=$argn[$i++];  # loop through input
$p=$c)                  # 2. remember character
$c<A # 1. if digit ?print$c            # then print it
:$s=($p<A           # else if previous character was digit
?!print$s # then print and reset string :$s                 # else do nothing
).$c; # append current character to string echo$s;                 # print remaining string

• I mean you can use ~ instead of a& Jul 5 '17 at 12:05

# Japt, 18 14 bytes

r"(%D+)"pv ÏiZ


Try it

r"(%D+)"pv ÏiZ     :Implicit input of string
r                  :Replace
"(%D+)"           :Literal string
p          :Append
v         :  Lowercase resulting in the Regex /(\D+)(\d+)/g
Ï       :Pass each match through a function
i      :  To the first matched group prepend
Z     :  The second matched group

• Can you add the explanation?
– Jim
Jul 4 '17 at 18:48
• @Jim, it's just a port of my JS solution (Japt transpiles to JS), which should be pretty self-explanatory. If not, see the explanation in Okx's Retina solution; both of mine do the exact same thing. Jul 4 '17 at 18:55
• ??? @Downvoter: please provide feedback. Jul 4 '17 at 18:59
• @Shaggy you said it yourself, it's basically copy paste of Okx's solution and then you took it one step further to a language which compiles to the exact same code as your other answer. So I downvoted because this wasn't a unique solution, which doesn't use any interesting golfing techniques or ingenuity; rather a translation of another answer Jul 4 '17 at 21:25
• @Downgoat, thanks for commenting. However, I did not say I copied Okx's solution, I simply directed Jim there for the explanation. If you check the timestamps, you'll see that I posted my JS solution at almost the same time as Okx (I may even have been first, but I can't see exact timestamps on mobile). I then ported my own solution to another language, which happens all the time here so, unless you're downvoting all ports, I don't understand why you've singled this one out. Jul 4 '17 at 22:07

# PHP, 45 bytes

<?=preg_replace("#(\D+)(\d+)#","$2$1",$argn);  Try it online! # C#, 71 bytes s=>System.Text.RegularExpressions.Regex.Replace(s,@"(\D+)(\d+)","$2$1")  Just a shame regular expressions are so long in C#. Try it online! Full/Formatted version: using System; class P { static void Main() { Func<string, string> f = s => System.Text.RegularExpressions.Regex.Replace(s, @"(\D+)(\d+)", "$2$1"); Console.WriteLine(f("uV5Pt3I0")); Console.WriteLine(f("J0i0m8")); Console.WriteLine(f("abc256")); Console.WriteLine(f("Hennebont56Fr")); Console.WriteLine(f("Em5sA55Ve777Rien")); Console.WriteLine(f("nOoP")); Console.ReadLine(); } }  • Can you add a link to TIO? – Jim Jul 5 '17 at 8:21 • @Jim Done. I'm usually too lazy to add it initially, especially whilst I'm still looking for any improvements. Jul 5 '17 at 8:24 ## Clojure, 104 88 bytes Oh regex is really handy... anyway (TIO): #(apply str(flatten(map reverse(partition-all 2(partition-by(fn[i](< 47(int i)58))%)))))  partition-by splits into consecutive runs based on the return value of that function, partition-all splits into partitions of 2 (the pairs we'll be swapping), map reverse reverses them, flatten gets rid of nested list structure and finally we'll output a string. If partition was used instead of partition-all and we had odd number of chunks then the last one would be discarded. Original used verbose but fun (juxt second first) and (set"0123456789") instead of reverse and ASCII integer ranges. #(apply str(flatten(map(juxt second first)(partition-all 2(partition-by(comp not(set"0123456789"))%)))))  • Can you add a link to TIO and an explanation? – Jim Jul 4 '17 at 18:36 # QuadR, 15 bytes (\D+)(\d+) \2\1  Try it online! ### Explanation blatantly stolen from Okx: This replaces the regex (\D+)(\d+) with \2\1. Let's break that down if you don't know what that means. The \D means 'match anything that isn't a number'. \d means 'match everything that is a number'. The + sign means 'match this at least once but try to match it as many times as possible'. The brackets define a group. The first group is (\D+) and the second is (\d+) In the second line we say that we want to put whatever was matched by the second group, followed by whatever was matched by the first group. This effectively swaps the letter and digit runs. # PowerShell, 40 bytes $args|%{$_ -replace '(\D+)(\d+)','$2\$1'}


Try it online!

PowerShell is pretty ideal for this, seeing that it supports regex search-and-replace out of box. Props go to @Okx for the regex solution.

# Pip, 17 bytes

aR-C+XL.C+XD{c.b}


Takes input as a command-line argument. Try it online!

### Explanation

This uses the standard regex-replacement strategy, somewhat golfed.

The regex is -C+XL.C+XD, which evaluates to (?i)([a-z]+)(\d+):

   XL       Preset regex variable for lowercase letter: [a-z]
+         Apply + to the regex: [a-z]+
C          Wrap the regex in a capturing group: ([a-z]+)
-           Apply the case-insensitive flag: (?i)([a-z]+)
XD  Preset regex variable for digit: \d
+    Apply + to the regex: \d+
C     Wrap the regex in a capturing group: (\d+)
.      Concatenate the two regexes: (?i)([a-z]+)(\d+)


The replacement is {c.b}, a callback function that concatenates the second group (c) and the first group (b). (The first argument to the function, a, contains the whole match.)

This is three bytes shorter than the naive aR(\D+)(\d+)\2\1.

# brainfuck, 98 bytes

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


Try it online!

### Explanation

This program maintains a queue of letters than haven't been output yet, and outputs them when appropriate.

The key to this program is >>----[---->+<<<-[>]>]. The three cells right of the input cell start out at zero. If the input is a code point between 1 and 63 inclusive, this moves the pointer one space right and places the input two spaces right of this new position. Otherwise, the pointer moves two spaces right, the cell one space right of the new position becomes 63, and the same 63 is subtracted from the input cell. This neatly divides the input into letters (65-122) and digits (48-57).

,[                       Take first input byte and start main loop
>>                     Move two cells to the right
----[---->+<<<-[>]>]   (See above)
>>                     Move two cells to the right
This cell contains the input if it was a digit, and 0 if input was a letter
[                      If input was a digit:
.                     Output digit immediately
[[-]<]                Zero out digit and working cell
<<[-]+>>              Set flag so we know later that we've output a digit
]
<                      Move one cell left
This cell contains 63 if input was a letter, and 0 if input was a digit
[                      If input was a letter:
[-<<<+>>>]            Add 63 back to input letter
<<<<                  Move to flag
[                     If a digit has been output since the last letter read:
-                    Clear flag
<[<]>                Move to start of queue
[.[-]>]              Output and clear all queued letters
]
>[-<+>]>              Move input to end of queue
]
,]                       Repeat until no input remains
<[-]                     Clear flag if present
<[<]>                    Move to start of queue
[.>]                     Output all queued letters

• Congratulation for having a brainfuck answer which is not the longest of the answers!
– Jim
Jul 6 '17 at 7:31

# Ruby, 31 bytes

->x{x.gsub /(\D+)(\d+)/,'\2\1'}


Try it online!

# Mathematica, 129 bytes

(n=NumberString;l=Length;s=Riffle[a=StringCases[#,n],b=StringSplit[#,n]];If[l@a==0,s=#,If[l@a<l@b,AppendTo[s,b[[-2;;]]]]];""<>s)&

• Can you add an explanation / ungolfed version?
– Jim
Jul 5 '17 at 9:30
• nothing much to explain...detects NumberString divides into 2 sets and riffles.Plus some "If" conditions in order to work perfectly Jul 5 '17 at 9:50