16
\$\begingroup\$

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.

\$\endgroup\$
0

25 Answers 25

15
\$\begingroup\$

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!

\$\endgroup\$
9
\$\begingroup\$

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.
\$\endgroup\$
7
\$\begingroup\$

Haskell, 58 56 bytes

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
\$\endgroup\$
3
  • \$\begingroup\$ Save two bytes with (a,(b,y))<-span(<':')<$>span(>'9')s. \$\endgroup\$
    – Laikoni
    Jul 5, 2017 at 5:38
  • 1
    \$\begingroup\$ Save even more with (a,(b,y):_)<-lex<$>span(>'9')s: Try it online! \$\endgroup\$
    – Laikoni
    Jul 5, 2017 at 6:03
  • \$\begingroup\$ @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 \$\endgroup\$ Jul 5, 2017 at 6:11
7
\$\begingroup\$

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>

\$\endgroup\$
6
\$\begingroup\$

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

Test suite.

\$\endgroup\$
6
\$\begingroup\$

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!

\$\endgroup\$
6
\$\begingroup\$

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
\$\endgroup\$
1
  • \$\begingroup\$ Was trying to figure out if there was a way to do it with ò. \$\endgroup\$
    – Shaggy
    Jul 4, 2017 at 19:08
5
\$\begingroup\$

CJam, 32 30 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.
\$\endgroup\$
4
\$\begingroup\$

Gema, 11 characters

<L><D>=$2$1

Sample run:

bash-4.4$ gema '<L><D>=$2$1' <<< 'Em5sA55Ve777Rien'
5Em55sA777VeRien
\$\endgroup\$
6
  • \$\begingroup\$ So...short. I mean, it's not a golfing language and just 11? Wow. \$\endgroup\$ Jul 5, 2017 at 8:02
  • \$\begingroup\$ Yeah, but only for tasks which not require touching the same input twice. Then it becomes nightmare. ☹ \$\endgroup\$
    – manatwork
    Jul 5, 2017 at 8:27
  • \$\begingroup\$ Found Gema through one of your other posts... cool language. Just how obscure would you say Gema is? \$\endgroup\$
    – Jonah
    Feb 2, 2018 at 0:50
  • \$\begingroup\$ @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.) \$\endgroup\$
    – manatwork
    Feb 2, 2018 at 9:10
  • \$\begingroup\$ 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? \$\endgroup\$
    – Jonah
    Feb 2, 2018 at 12:44
3
\$\begingroup\$

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.

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

Sed, 29 bytes

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

Run with -r.

Uses capture groups and replaces them in the opposite order.

\$\endgroup\$
6
  • \$\begingroup\$ You can shorten [A-Za-z] to [^0-9]. However, you have to count the flag as part of your code. \$\endgroup\$
    – Dennis
    Jul 4, 2017 at 20:45
  • \$\begingroup\$ How much does the flag count as? \$\endgroup\$
    – It Guy
    Jul 4, 2017 at 20:47
  • \$\begingroup\$ The difference between sed <command> and sed -r <command>, so three bytes. \$\endgroup\$
    – Dennis
    Jul 4, 2017 at 20:50
  • \$\begingroup\$ @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. \$\endgroup\$ Jul 5, 2017 at 12:15
  • \$\begingroup\$ 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. \$\endgroup\$ Jul 5, 2017 at 12:17
2
\$\begingroup\$

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
\$\endgroup\$
2
  • 2
    \$\begingroup\$ Can you add the explanation? \$\endgroup\$
    – Jim
    Jul 4, 2017 at 18:34
  • \$\begingroup\$ @Jim Added explanaion. \$\endgroup\$ Jul 5, 2017 at 7:55
2
\$\begingroup\$

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
\$\endgroup\$
1
  • \$\begingroup\$ I mean you can use ~ instead of a& \$\endgroup\$ Jul 5, 2017 at 12:05
2
\$\begingroup\$

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
\$\endgroup\$
5
  • \$\begingroup\$ Can you add the explanation? \$\endgroup\$
    – Jim
    Jul 4, 2017 at 18:48
  • \$\begingroup\$ @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. \$\endgroup\$
    – Shaggy
    Jul 4, 2017 at 18:55
  • 4
    \$\begingroup\$ ??? @Downvoter: please provide feedback. \$\endgroup\$
    – Shaggy
    Jul 4, 2017 at 18:59
  • \$\begingroup\$ @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 \$\endgroup\$
    – Downgoat
    Jul 4, 2017 at 21:25
  • 1
    \$\begingroup\$ @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. \$\endgroup\$
    – Shaggy
    Jul 4, 2017 at 22:07
1
\$\begingroup\$

PHP, 45 bytes

<?=preg_replace("#(\D+)(\d+)#","$2$1",$argn);

Try it online!

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

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();
    }
}
\$\endgroup\$
2
  • \$\begingroup\$ Can you add a link to TIO? \$\endgroup\$
    – Jim
    Jul 5, 2017 at 8:21
  • \$\begingroup\$ @Jim Done. I'm usually too lazy to add it initially, especially whilst I'm still looking for any improvements. \$\endgroup\$ Jul 5, 2017 at 8:24
1
\$\begingroup\$

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"))%)))))
\$\endgroup\$
1
  • \$\begingroup\$ Can you add a link to TIO and an explanation? \$\endgroup\$
    – Jim
    Jul 4, 2017 at 18:36
1
\$\begingroup\$

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.

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

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.

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

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`.

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

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
\$\endgroup\$
1
  • \$\begingroup\$ Congratulation for having a brainfuck answer which is not the longest of the answers! \$\endgroup\$
    – Jim
    Jul 6, 2017 at 7:31
1
\$\begingroup\$

Ruby, 31 bytes

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

Try it online!

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

Vyxal, 40 bitsv2, 5 bytes

⁽±Ḋ2ẇvṘ

Try it Online!

Bitstring:

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

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)&
\$\endgroup\$
2
  • \$\begingroup\$ Can you add an explanation / ungolfed version? \$\endgroup\$
    – Jim
    Jul 5, 2017 at 9:30
  • \$\begingroup\$ nothing much to explain...detects NumberString divides into 2 sets and riffles.Plus some "If" conditions in order to work perfectly \$\endgroup\$
    – ZaMoC
    Jul 5, 2017 at 9:50
0
\$\begingroup\$

Scala, 89 bytes

A port of @Julian Wolf's Haskell answer in Scala.


Golfed version. Try it online!

s=>s match{case""=>"";case s=>{val(l,a)=s.span(_>'9');val(n,a2)=a.span(_<':');n+l+f(a2)}}

Ungolfed version. Try it online!

object Main extends App {

  def f(string: String): String = {
    string match {
      case "" => ""
      case str => 
        val (letters, afterLetters) = str.span(_ > '9')
        val (numbers, afterNumbers) = afterLetters.span(_ < ':')
        numbers + letters + f(afterNumbers) 
    }
  }

  println(s"uV5Pt3I0         -> ${f("uV5Pt3I0")}")
  println(s"J0i0m8           -> ${f("J0i0m8")}") 
  println(s"abc256           -> ${f("abc256")}")
  println(s"Hennebont56Fr    -> ${f("Hennebont56Fr")}")
  println(s"Em5sA55Ve777Rien -> ${f("Em5sA55Ve777Rien")}")
  println(s"nOoP             -> ${f("nOoP")}")

}
\$\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.