18
\$\begingroup\$

This problem is about separating a string representing a product identifier into three components.

  • The first part consists of upper and lower letters of arbitrary length which represents the warehouse.
  • The second part is digits which represents the product number. This part is also of arbitrary length.
  • The last part is qualifiers as size and colours, and this part continues to the end of the string. The qualifiers are guaranteed to start with a capital letter and consist of alphanumeric characters.

Each part should be printed clearly separated. It is guaranteed that each part is non-empty.

The winner is the one who uses least bytes to solve this problem.

Example:
Input: UK7898S14

Output:
UK
7898
S14

Here UK is United Kingdom, 7898 is the product code, and S14 is size 14.

Example 2:
Input: cphDK1234CYELLOWS14QGOOD

Output:
cphDK
1234
CYELLOWS14QGOOD

Here cphDK is Copenhagen, Denmark, 1234 is the product code, CYELLOWS14QGOOD represents yellow colour, size 14, and good quality.

\$\endgroup\$
7
  • 2
    \$\begingroup\$ Is each part non-empty? \$\endgroup\$
    – Karl Napf
    Commented Nov 8, 2016 at 9:10
  • \$\begingroup\$ @KarlNapf Yes. Each part is non-empty. \$\endgroup\$
    – Zinoex
    Commented Nov 8, 2016 at 9:13
  • \$\begingroup\$ @Emigna An addition example has now been included. \$\endgroup\$
    – Zinoex
    Commented Nov 8, 2016 at 9:18
  • \$\begingroup\$ “The first part consists of upper and lower letters” – Maybe one of the examples could contain such mixture of upper and lowercase letters. And maybe also a country code that is not 2 characters long. Also, could the qualifier contain non-alphanumeric characters, like “Quality★★★☆☆”? \$\endgroup\$
    – manatwork
    Commented Nov 8, 2016 at 9:21
  • \$\begingroup\$ Welcome to PPCG! \$\endgroup\$ Commented Nov 8, 2016 at 12:30

25 Answers 25

10
\$\begingroup\$

Perl, 12 bytes

11 bytes of code + 1 byte for -p flag.

s/\d+/
$&
/

To run it :

perl -pe 's/\d+/
$&
/' <<< "CYELLOWS14QGOOD"
\$\endgroup\$
1
  • 2
    \$\begingroup\$ Love the simplicity! :) \$\endgroup\$ Commented Nov 8, 2016 at 12:59
4
\$\begingroup\$

APL, 18

{⍵⊂⍨3⌊+\1,2≠/⍵∊⎕D}'UK7898S14'
UK  7898  S14 

Works by searching the first 2 points where there is a change from character to digit or vice-versa, and using those to split the string.

\$\endgroup\$
4
\$\begingroup\$

Retina, 28 14 10 8 bytes

Saved 4 bytes thanks to Dom Hastings.
Saved 2 bytes thanks to Martin Ender.

S1`(\d+)

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ Using the same mechanism as @Dada's answer, you can save another 4 bytes: retina.tryitonline.net/… (tbh, probably even more, but that's all I could save! :)) \$\endgroup\$ Commented Nov 8, 2016 at 12:58
  • \$\begingroup\$ @DomHastings. Aah, nice idea going with the replace! \$\endgroup\$
    – Emigna
    Commented Nov 8, 2016 at 13:15
3
\$\begingroup\$

Haskell, 36 bytes (no regex)

d c='/'<c&&c<':'
(span d<$>).break d

This gives the result in the format ("UK",("7898","S14")). The idea is to split at the first digit, and then split the rest at the first non-digit. Try it on Ideone.

\$\endgroup\$
1
  • \$\begingroup\$ Nice use of fmap on a tuple. \$\endgroup\$
    – xnor
    Commented Nov 8, 2016 at 17:44
3
\$\begingroup\$

JavaScript, 38 36 bytes

s=>/(\D+)(\d+)(.+)/.exec(s).slice(1)

Example

const f =

s=>/(\D+)(\d+)(.+)/.exec(s).slice(1)

console.log(f("UK7898S14"));
console.log(f("cphDK1234CYELLOWS14QGOOD"));

\$\endgroup\$
1
  • \$\begingroup\$ @Arnauld Good catch. \$\endgroup\$
    – Florent
    Commented Nov 8, 2016 at 15:01
3
\$\begingroup\$

JavaScript (ES6), 28 26 bytes

s=>s.replace(/\d+/,`
$&
`)

Saved 2 bytes thanks to @Grax

Examples

let f =

s=>s.replace(/\d+/,`
$&
`)

console.log(f('UK7898S14'));
console.log(f('cphDK1234CYELLOWS14QGOOD'));

\$\endgroup\$
1
  • \$\begingroup\$ You can reduce 2 more characters by using $& in your replace and removing the parentheses. s=>s.replace(/\d+/,` $& `) \$\endgroup\$
    – Grax32
    Commented Nov 9, 2016 at 17:36
2
\$\begingroup\$

Gema, 17 12 characters

(The trick of not handling the country code explicitly shamelessly borrowed from Dada's Perl solution. Appreciation should be expressed there.)

<D>*=\n$1\n*

Sample run:

bash-4.3$ gema '<D>*=\n$1\n*' <<< 'UK7898S14'
UK
7898
S14

bash-4.3$ gema '<D>*=\n$1\n*' <<< 'cphDK1234CYELLOWS14QGOOD'
cphDK
1234
CYELLOWS14QGOOD
\$\endgroup\$
2
\$\begingroup\$

Python 2, 40 Bytes

I don't know much Regex, but thankfully this problem is simple enough :) Seperates the input string into a list of length 3 which contains each part.

import re
lambda k:re.split('(\d+)',k,1)
\$\endgroup\$
2
\$\begingroup\$

05AB1E, 39 37 16 bytes

Saved a lot of bytes thanks to Emigna.

It uses CP-1252 encoding.

TvDSdykF¬?¦}¶?}?

T                push "10"
 v               for each element (i.e., 1 and 0). Element is stored in 'y'
  DS             split string (input during the first iteration)
    d            for each character, 1 if digit or 0 otherwise
     yk          get index of the first occurrence of 'y'
       F         for 0 <= i < string.firstIndexOf(y)
        ¬?       print the first character of the string
          ¦      remove it from the string
           }     end inner for
            ¶?   display a newline
              }  end outer for
               ? display the remaining string

Try it online!

(This is my first post here!)

\$\endgroup\$
5
  • \$\begingroup\$ You can save at least 14 bytes by checking digits instead of letters. And this can likely be golfed more. \$\endgroup\$
    – Emigna
    Commented Nov 8, 2016 at 13:26
  • \$\begingroup\$ Also, welcome to PPCG :) \$\endgroup\$
    – Emigna
    Commented Nov 8, 2016 at 14:15
  • \$\begingroup\$ Thanks! And you are right, actually I went all naive on this one, literally from left to right. I also tried to dig .páଠto get the first part, but it doesn't seem to help for the rest at first glance. \$\endgroup\$
    – Osable
    Commented Nov 8, 2016 at 17:54
  • \$\begingroup\$ Feel free to update your answer with my code (and golf it some more if you can). I don't feel that it's different enough to warrant it's own answer. \$\endgroup\$
    – Emigna
    Commented Nov 8, 2016 at 18:12
  • \$\begingroup\$ Ok I'll do it then as I found a way to put it in a loop. Nothing too sophisticated, but at least it goes down to 16 bytes. Thank you again! (Now I have to update the explanations... but there are fewer bytes to explain) \$\endgroup\$
    – Osable
    Commented Nov 8, 2016 at 18:38
1
\$\begingroup\$

JavaScript (ES6), 36 bytes

s=>/(.+?)(\d+)(.*)/.exec(s).slice(1)

Examples

let f =

s=>/(.+?)(\d+)(.*)/.exec(s).slice(1)

console.log(f('UK7898S14'));
console.log(f('cphDK1234CYELLOWS14QGOOD'));

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

Java 7, 200 185 174 167 bytes

import java.util.regex.*;String c(String s){Matcher m=Pattern.compile("(.*?)(\\d+)(.*)").matcher(s);s="";for(int i=0;i<3;)if(m.matches())s+=m.group(++i)+" ";return s;}

Ungolfed & test code:

Try it here.

import java.util.regex.*;
class M{
  static String c(String s){
    Matcher m = Pattern.compile("(.*?)(\\d+)(.*)").matcher(s);
    s = "";
    for(int i = 0; i < 3;){
      if(m.matches()){
        s += m.group(++i) + " ";
      }
    }
    return s;
  }

  public static void main(String[] a){
    System.out.println(c("UK7898S14"));
    System.out.println(c("cphDK1234CYELLOWS14QGOOD"));
  }
}

Output:

UK 7898 S14 
cphDK 1234 CYELLOWS14QGOOD 
\$\endgroup\$
1
\$\begingroup\$

C#, 191 177 bytes

Golfed:

void F(string s){var a=s.ToList();int i=a.FindIndex(char.IsDigit);int n=a.FindIndex(i,char.IsUpper);Console.Write($"{s.Substring(0,i)}\n{s.Substring(i,n-i)}\n{s.Substring(n)}");

Ungolfed:

    void F(string s)
    {
        var a = s.ToList();
        int i = a.FindIndex(char.IsDigit);
        int n = a.FindIndex(i, char.IsUpper);

        Console.Write($"{s.Substring(0, i)}\n{s.Substring(i, n - i)}\n{s.Substring(n)}");
    }

EDIT1: @Link Ng saved 14 bytes.

\$\endgroup\$
2
  • \$\begingroup\$ You don't need ToCharArray(). string is already IEnumerable<char> \$\endgroup\$
    – Link Ng
    Commented Nov 8, 2016 at 12:36
  • \$\begingroup\$ Of course, I can't believe I didn't notice this. \$\endgroup\$
    – paldir
    Commented Nov 8, 2016 at 12:41
1
\$\begingroup\$

PHP, 48 bytes

print_r(preg_split('/(\D+|\d+)\K/',$argv[1],3));

With its $limit parameter, and the fantastically useful \K, preg_split() is perfect for this challenge.

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

MATLAB, 81 73 bytes

function y=f(x)
[~,~,~,m,~,~,s]=regexp(x,'(?<=^\D+)\d+');y=[s(1) m s(2)];

Function that accepts a string and returns a cell array of three strings. Tested in version R20105b.

Example use:

>> f('UK7898S14')
ans = 
    'UK'    '7898'    'S14'

>> f('cphDK1234CYELLOWS14QGOOD')
ans = 
    'cphDK'    '1234'    'CYELLOWS14QGOOD'

Explanation

The regular expression (?<=^\D+)\d+') matches a group of digits preceded by non-digits from the start of the string; the latter are not part of the match.

The fourth output of regexp is the 'match'; and the seventh output is the 'split', that is, the two parts of the string before and after the match.

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

Ruby, 28 bytes

->s{puts s.sub(/\d+/,"\n\\&\n")}

This surrounds the first cluster of digits with newlines.

\$\endgroup\$
1
  • \$\begingroup\$ 16 bytes with the -p switch, no parentheses, single quotes, and literal newlines. \$\endgroup\$
    – Jordan
    Commented Aug 27 at 15:05
0
\$\begingroup\$

jq, 47 characters

(43 characters code + 4 characters command line options.)

match("(\\D+)(\\d+)(.+)").captures[].string

(Again the old story: fairly elegant at the beginning, then becomes painfully verbose.)

Sample run:

bash-4.3$ jq -Rr 'match("(\\D+)(\\d+)(.+)").captures[].string' <<< 'UK7898S14'
UK
7898
S14

bash-4.3$ jq -Rr 'match("(\\D+)(\\d+)(.+)").captures[].string' <<< 'cphDK1234CYELLOWS14QGOOD'
cphDK
1234
CYELLOWS14QGOOD

On-line test (Passing -r through URL is not supported – check Raw Output yourself.)

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

PHP, 61 59 5655 bytes

preg_match('/(\D+)(\d+)(.+)/',$argv[1],$a);print_r($a);

This does output the initial code as well:

Array
(
    [0] => cphDK1234CYELLOWS14QGOOD
    [1] => cphDK
    [2] => 1234
    [3] => CYELLOWS14QGOOD
)

Edit

Thanks to @manatwork for saving a few bytes for me
Thanks to @RomanGräf for another few bytes saved

\$\endgroup\$
6
  • 1
    \$\begingroup\$ [\d]? :o \d is enough. \$\endgroup\$
    – manatwork
    Commented Nov 8, 2016 at 10:49
  • \$\begingroup\$ @manatwork Thanks. I don't use regex enough (arguably a good thing) and started down the [0-9]+ route before remembering about \d \$\endgroup\$
    – gabe3886
    Commented Nov 8, 2016 at 10:53
  • 1
    \$\begingroup\$ Why not replace [a-z] with \D? \$\endgroup\$ Commented Nov 8, 2016 at 12:05
  • 1
    \$\begingroup\$ Now that you have no [a-z], the i flag is not needed either. \$\endgroup\$
    – manatwork
    Commented Nov 8, 2016 at 12:24
  • \$\begingroup\$ I really need to pend more time working on regular expressions. \$\endgroup\$
    – gabe3886
    Commented Nov 8, 2016 at 12:30
0
\$\begingroup\$

JavaScript without regex, 84 81 79 bytes

p=>{for(i=n=o='';i<p.length;){if(n==isNaN(c=p[i++])){o+=' ';n++}o+=c}return o}

\$\endgroup\$
8
  • 2
    \$\begingroup\$ You could put all initializations in a single place: o=n=i=''. \$\endgroup\$
    – manatwork
    Commented Nov 8, 2016 at 11:16
  • \$\begingroup\$ And move the assignment to c to its first usage: isNaN(c=p[i++]). \$\endgroup\$
    – manatwork
    Commented Nov 8, 2016 at 11:36
  • \$\begingroup\$ p=>{for(i=n=o=0;i<p.length;){c=p[i++];if(n++==c<59){o+=' '}o+=c}return o} \$\endgroup\$ Commented Nov 8, 2016 at 12:16
  • \$\begingroup\$ @RomanGräf, the initialization should remain '' because the o, to which the result will be concatenated. But sadly your code is not working for me, n needs to be incremented conditionally. \$\endgroup\$
    – manatwork
    Commented Nov 8, 2016 at 12:29
  • \$\begingroup\$ p=>{for(i=n=0,o='';i<p.length;){c=p[i++];if(n==c<59){o+=' ';n++}o+=c}return o} \$\endgroup\$ Commented Nov 8, 2016 at 12:31
0
\$\begingroup\$

Mathematica, 39 bytes

StringSplit[#,a:DigitCharacter..:>a,2]&

Anonymous function. Takes a string as input, and returns a list of strings as output.

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

Racket 274 bytes

(let((g 0)(j'())(k'())(l'())(m list->string)(r reverse)(n char-numeric?)(c cons))(for((i(string->list s)))
(when(and(= g 0)(n i))(set! g 1))(when(and(= g 1)(not(n i)))(set! g 2))(match g[0(set! j(c i j))]
[1(set! k(c i k))][2(set! l(c i l))]))(list(m(r j))(m(r k))(m(r l))))

Ungolfed:

(define (f s)
  (let ((g 0)
        (j '())
        (k '())
        (l '())
        (m list->string)
        (r reverse)
        (n char-numeric?)
        (c cons))
    (for ((i (string->list s)))
      (when (and (= g 0) (n i)) (set! g 1)  )
      (when (and (= g 1) (not (n i))) (set! g 2) )
      (match g
        [0 (set! j (c i j))]
        [1 (set! k (c i k))]
        [2 (set! l (c i l))]))
    (list (m (r j)) (m (r k)) (m (r l)))))

Testing:

(f "UK7898S14")
(f "cphDK1234CYELLOWS14QGOOD")

Output:

'("UK" "7898" "S14")
'("cphDK" "1234" "CYELLOWS14QGOOD")
\$\endgroup\$
0
\$\begingroup\$

R, 63 52 bytes

Edit: Saved a bunch of bytes thanks to @JDL

Takes input from stdin and prints to stdout:

gsub("([a-z]+)(\\d+)(.+)","\\1 \\2 \\3",scan(,""),T)

Example output:

[1] "UK 7898 S1"
[1] "cphDK 1234 CYELLOWS14QGOOD"
\$\endgroup\$
6
  • \$\begingroup\$ Wouldn't gsub (...,"\\1 \\2 \\3") be more efficient? \$\endgroup\$
    – JDL
    Commented Nov 8, 2016 at 15:08
  • \$\begingroup\$ @JDL Not sure I follow. Care to elaborate or give an example? \$\endgroup\$
    – Billywob
    Commented Nov 8, 2016 at 15:17
  • \$\begingroup\$ something like gsub("([A-Za-z]+)([0-9]+)(.+)","\\1 \\2 \\3",scan()), though the first argument can probably be expressed as something smaller than that... \$\endgroup\$
    – JDL
    Commented Nov 8, 2016 at 15:31
  • \$\begingroup\$ @JDL Very clever but I have no idea how the "\\1 \\2 \\3" replacement works though. Also updated the regex pattern a bit and use ignore.case = TRUE. \$\endgroup\$
    – Billywob
    Commented Nov 8, 2016 at 15:38
  • \$\begingroup\$ They just mean "output whatever was captured in the first/second/third pair of () brackets. \$\endgroup\$
    – JDL
    Commented Nov 8, 2016 at 15:42
0
\$\begingroup\$

Jelly, 14 bytes

O<65ITḣ2‘ṬœṗµY

TryItOnline!

How?

O<65ITḣ2‘ṬœṗµY - Main link: productIdentifier   e.g. "UK7898S14"
O              - cast to ordinals               e.g. [85,75,55,56,57,56,83,49,52]
 <65           - less than 65?                  e.g. [ 0, 0, 1, 1, 1, 1, 0, 1, 1]
    I          - incremental difference         e.g. [ 0, 1, 0, 0, 0,-1, 1, 0]
     T         - truthy indexes                 e.g. [2, 6, 7]
      ḣ2       - head to 2                      e.g. [2, 6]
        ‘      - increment                      e.g. [3, 7]
         Ṭ     - set truthy indexes             e.g. [0, 0, 1, 0, 0, 0, 1]
          œṗ   - split y at truthy indexes of x e.g. ["UK", "7898", "S14"]
            µ  - monadic chain separation
             Y - join with line feeds
\$\endgroup\$
0
\$\begingroup\$

C, 107 bytes

#define p(x) printf("%c",x);
f(char*s){for(;*s>64;s++)p(*s)p(10)for(;*s<58;s++)p(*s)p(10)for(;*s;s++)p(*s)}

Call with:

int main()
{
   f("UK7898S14");
   return 0;
}
\$\endgroup\$
0
\$\begingroup\$

Python 2, 103 94 88 bytes

Solution without using regex

a,b=input(),""
for f in a:
 if ord(f)<58:b+=f
 elif b"":c,d=a.split(b);print c,b,d;break

Simply extracts the numbers from the middle then slices the input using the number as an index. Requires quotes around the input but I didn't see anywhere that quotes are disallowed.

-9 by splitting a on the middle number then print the components with b in the middle

-6 Thanks to @Shebang

Test Cases

D:\>python codes.py
"UK7898S14"
UK 7898 S14

D:\>python codes.py
"cphDK1234CYELLOWS14QGOOD"
cphDK 1234 CYELLOWS14QGOOD
\$\endgroup\$
3
  • \$\begingroup\$ b!="" -> b>"" and c=a.split(b) -> c,d=a.split(b) ... print c[0],b,c[1] -> print c,b,d saves 5 bytes. \$\endgroup\$
    – Kade
    Commented Nov 9, 2016 at 15:13
  • \$\begingroup\$ Very nice hints @Shebang. Thanks \$\endgroup\$
    – ElPedro
    Commented Nov 9, 2016 at 15:21
  • \$\begingroup\$ Ah, I forgot empty strings are falsy. You can save another 3 bytes by just making it elif b: ;) \$\endgroup\$
    – Kade
    Commented Nov 9, 2016 at 15:32
0
\$\begingroup\$

C#, 74 bytes

v=>new System.Text.RegularExpressions.Regex("\\d+").Replace(v,"\n$&\n",1);

Replace 1st set of digits with carriage return, set of digits, and another carriage return, as Johan Karlsson did for JavaScript.

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