17
\$\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\$
  • 2
    \$\begingroup\$ Is each part non-empty? \$\endgroup\$ – Karl Napf Nov 8 '16 at 9:10
  • \$\begingroup\$ @KarlNapf Yes. Each part is non-empty. \$\endgroup\$ – Highace2 Nov 8 '16 at 9:13
  • \$\begingroup\$ @Emigna An addition example has now been included. \$\endgroup\$ – Highace2 Nov 8 '16 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 Nov 8 '16 at 9:21
  • \$\begingroup\$ Welcome to PPCG! \$\endgroup\$ – Erik the Outgolfer Nov 8 '16 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\$
  • 2
    \$\begingroup\$ Love the simplicity! :) \$\endgroup\$ – Dom Hastings Nov 8 '16 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\$
  • \$\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\$ – Dom Hastings Nov 8 '16 at 12:58
  • \$\begingroup\$ @DomHastings. Aah, nice idea going with the replace! \$\endgroup\$ – Emigna Nov 8 '16 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\$
  • \$\begingroup\$ Nice use of fmap on a tuple. \$\endgroup\$ – xnor Nov 8 '16 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\$
  • \$\begingroup\$ @Arnauld Good catch. \$\endgroup\$ – Florent Nov 8 '16 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\$
  • \$\begingroup\$ You can reduce 2 more characters by using $& in your replace and removing the parentheses. s=>s.replace(/\d+/,` $& `) \$\endgroup\$ – Grax Nov 9 '16 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\$
  • \$\begingroup\$ You can save at least 14 bytes by checking digits instead of letters. And this can likely be golfed more. \$\endgroup\$ – Emigna Nov 8 '16 at 13:26
  • \$\begingroup\$ Also, welcome to PPCG :) \$\endgroup\$ – Emigna Nov 8 '16 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 Nov 8 '16 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 Nov 8 '16 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 Nov 8 '16 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\$
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\$
  • \$\begingroup\$ You don't need ToCharArray(). string is already IEnumerable<char> \$\endgroup\$ – Link Ng Nov 8 '16 at 12:36
  • \$\begingroup\$ Of course, I can't believe I didn't notice this. \$\endgroup\$ – paldir Nov 8 '16 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\$
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\$
  • 1
    \$\begingroup\$ [\d]? :o \d is enough. \$\endgroup\$ – manatwork Nov 8 '16 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 Nov 8 '16 at 10:53
  • 1
    \$\begingroup\$ Why not replace [a-z] with \D? \$\endgroup\$ – Roman Gräf Nov 8 '16 at 12:05
  • 1
    \$\begingroup\$ Now that you have no [a-z], the i flag is not needed either. \$\endgroup\$ – manatwork Nov 8 '16 at 12:24
  • \$\begingroup\$ I really need to pend more time working on regular expressions. \$\endgroup\$ – gabe3886 Nov 8 '16 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\$
  • 2
    \$\begingroup\$ You could put all initializations in a single place: o=n=i=''. \$\endgroup\$ – manatwork Nov 8 '16 at 11:16
  • \$\begingroup\$ And move the assignment to c to its first usage: isNaN(c=p[i++]). \$\endgroup\$ – manatwork Nov 8 '16 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\$ – Roman Gräf Nov 8 '16 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 Nov 8 '16 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\$ – Roman Gräf Nov 8 '16 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\$
  • \$\begingroup\$ Wouldn't gsub (...,"\\1 \\2 \\3") be more efficient? \$\endgroup\$ – JDL Nov 8 '16 at 15:08
  • \$\begingroup\$ @JDL Not sure I follow. Care to elaborate or give an example? \$\endgroup\$ – Billywob Nov 8 '16 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 Nov 8 '16 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 Nov 8 '16 at 15:38
  • \$\begingroup\$ They just mean "output whatever was captured in the first/second/third pair of () brackets. \$\endgroup\$ – JDL Nov 8 '16 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\$
  • \$\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 Nov 9 '16 at 15:13
  • \$\begingroup\$ Very nice hints @Shebang. Thanks \$\endgroup\$ – ElPedro Nov 9 '16 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 Nov 9 '16 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, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.