# Product catalog

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.

• Is each part non-empty? Nov 8, 2016 at 9:10
• @KarlNapf Yes. Each part is non-empty. Nov 8, 2016 at 9:13
• @Emigna An addition example has now been included. Nov 8, 2016 at 9:18
• “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★★★☆☆”? Nov 8, 2016 at 9:21
• Welcome to PPCG! Nov 8, 2016 at 12:30

## Perl, 12 bytes

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

s/\d+/
$& /  To run it : perl -pe 's/\d+/$&
/' <<< "CYELLOWS14QGOOD"

• Love the simplicity! :) Nov 8, 2016 at 12:59

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

# Retina, 281410 8 bytes

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

S1(\d+)


Try it online!

• 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! :)) Nov 8, 2016 at 12:58
• @DomHastings. Aah, nice idea going with the replace! Nov 8, 2016 at 13:15

## 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. • Nice use of fmap on a tuple. – xnor Nov 8, 2016 at 17:44 # 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")); • @Arnauld Good catch. Nov 8, 2016 at 15:01 ## 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')); • You can reduce 2 more characters by using$& in your replace and removing the parentheses. s=>s.replace(/\d+/, $& ) Nov 9, 2016 at 17:36 # 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


# 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)


# 05AB1E, 3937 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!)

• You can save at least 14 bytes by checking digits instead of letters. And this can likely be golfed more. Nov 8, 2016 at 13:26
• Also, welcome to PPCG :) Nov 8, 2016 at 14:15
• 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. Nov 8, 2016 at 17:54
• 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. Nov 8, 2016 at 18:12
• 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) Nov 8, 2016 at 18:38

## 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'));

# Java 7, 200185174 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


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

• You don't need ToCharArray(). string is already IEnumerable<char> Nov 8, 2016 at 12:36
• Of course, I can't believe I didn't notice this. Nov 8, 2016 at 12:41

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

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

# Ruby, 28 bytes

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


This surrounds the first cluster of digits with newlines.

# 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.)

# 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 • [\d]? :o \d is enough. Nov 8, 2016 at 10:49 • @manatwork Thanks. I don't use regex enough (arguably a good thing) and started down the [0-9]+ route before remembering about \d Nov 8, 2016 at 10:53 • Why not replace [a-z] with \D? Nov 8, 2016 at 12:05 • Now that you have no [a-z], the i flag is not needed either. Nov 8, 2016 at 12:24 • I really need to pend more time working on regular expressions. Nov 8, 2016 at 12:30 # JavaScript without regex, 8481 79 bytes p=>{for(i=n=o='';i<p.length;){if(n==isNaN(c=p[i++])){o+=' ';n++}o+=c}return o} • You could put all initializations in a single place: o=n=i=''. Nov 8, 2016 at 11:16 • And move the assignment to c to its first usage: isNaN(c=p[i++]). Nov 8, 2016 at 11:36 • p=>{for(i=n=o=0;i<p.length;){c=p[i++];if(n++==c<59){o+=' '}o+=c}return o} Nov 8, 2016 at 12:16 • @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. Nov 8, 2016 at 12:29 • p=>{for(i=n=0,o='';i<p.length;){c=p[i++];if(n==c<59){o+=' ';n++}o+=c}return o} Nov 8, 2016 at 12:31 # Mathematica, 39 bytes StringSplit[#,a:DigitCharacter..:>a,2]&  Anonymous function. Takes a string as input, and returns a list of strings as output. ## 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")  # 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"  • Wouldn't gsub (...,"\\1 \\2 \\3") be more efficient? – JDL Nov 8, 2016 at 15:08 • @JDL Not sure I follow. Care to elaborate or give an example? Nov 8, 2016 at 15:17 • 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... – JDL Nov 8, 2016 at 15:31 • @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. Nov 8, 2016 at 15:38 • They just mean "output whatever was captured in the first/second/third pair of () brackets. – JDL Nov 8, 2016 at 15:42 # 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  # 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; }  # Python 2, 10394 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  • 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. – Kade Nov 9, 2016 at 15:13 • Very nice hints @Shebang. Thanks Nov 9, 2016 at 15:21 • Ah, I forgot empty strings are falsy. You can save another 3 bytes by just making it elif b: ;) – Kade Nov 9, 2016 at 15:32 # 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.