11
\$\begingroup\$

Inspired by this StackOverflow question.

Input:

We'll take three inputs:

  • A delimiter-character D to split on
  • A character I between two of which we ignore the delimiter character (I know, that sounds vague, but I'll explain it below)
  • A string S

Output:

A list/array containing the substrings after the split.

Example:

Input:
D = ','
I = '"'
S = '11020199,"Abc ",aduz,,444,bieb,dc,2 ,2222.00,whatever 5dc,222.22,22.00,"98,00","12,000,000",21-09-2018, 06:00,",-,"'

Output:
['11020199', 'Abc ', 'aduz', '', '444', 'bieb', 'dc', '2 ', '2222.00', 'whatever 5dc', '222.22', '22.00', '98,00', '12,000,000', '21-09-2018', ' 06:00', ',-,']

Why? Splitting on comma would normally also split 98,00, 12,000,000 and ,-, in two/three pieces. But because they are within the I input character, we ignore ignore the split here.

Challenge rules:

  • You can assume there will always be an even amount of I characters in the input-string.
  • You can assume the character I will always have a D next to it (except when it's the first or last character of the input) which can still be properly split. So you won't have something like D = ','; I = '"'; S = 'a,b"c,d"e,f', nor anything like this D=','; I='"'; S='a",b,"c'.
  • The input-string S could contain none of either D or I. If it contains no D, we output a list with the entire input-string as only item.
  • The output list won't contain the character I anymore, even when it contained no D (as you can see at the "Abc " becoming 'Abc ' in the example above).
  • It is possible that the substring within I contains only D. For example: D = ','; I = '"'; S = 'a,",",b,"c","d,e,,",f' would result in ['a', ',', 'b', 'c', 'd,e,,', 'f'].
  • You can assume that D will never be at the start or end of S, so you won't have to deal with trailing / leading empty items.
  • When an input has two adjacent D, we'll have an empty item. I.e. D = ','; I = '"'; S = 'a,"b,c",d,,e,"",f' would result in ['a', 'b,c', 'd', '', 'e', '', 'f'].
  • You can assume the inputs and outputs will only contain printable ASCII in the range [32, 126] (so excluding tabs and newlines).
  • You are also allowed to output all items new-line delimited instead of returning/outputting a list/array (especially for those languages that don't have lists/arrays; i.e. Retina).
  • You are allowed to output the list in reversed order if it saves bytes. You are not allowed to output it in sorted or 'shuffled' order, though. So D = ','; I = 'n'; S = 'a,2,b,3,c' can be output as [a,2,b,3,c] or [c,3,b,2,a], but not as [2,3,a,b,c,] or [a,3,b,c,2] for example.

General rules:

  • This is , so shortest answer in bytes wins.
    Don't let code-golf languages discourage you from posting answers with non-codegolfing languages. Try to come up with an as short as possible answer for 'any' programming language.
  • Standard rules apply for your answer, so you are allowed to use STDIN/STDOUT, functions/method with the proper parameters and return-type, full programs. Your call.
  • Default Loopholes are forbidden.
  • If possible, please add a link with a test for your code (i.e. TIO).
  • Also, adding an explanation for your answer is highly recommended.

Test cases:

Input:
D = ','; I = '"'; S = 'a,"b,c",d,,e,"",f'
Output:
['a', 'b,c', 'd', '', 'e', '', 'f']

Input:
D = ','; I = '"'; S = '11020199,"Abc ",aduz,,444,bieb,dc,2 ,2222.00,whatever 5dc,222.22,22.00,"98,00","12,000,000",21-09-2018, 06:00,",-,"'
Output:
['11020199', 'Abc ', 'aduz', '', '444', 'bieb', 'dc', '2 ', '2222.00', 'whatever 5dc', '222.22', '22.00', '98,00', '12,000,000', '21-09-2018', ' 06:00', ',-,']

Input:
D = ' '; I = ','; S = 'this is a test , to see if you understand it, or not , hmmm, I think I have too many commas , or not , perhaps..'
Output:
['this', 'is', 'a', 'test', ' to see if you understand it', 'or', 'not', ' hmmm', 'I', 'think', 'I', 'have', 'too', 'many', 'commas', ' or not ', 'perhaps..']

Input:
D = 'x'; I = 'y'; S = 'contains no lowercase X nor Y'
Output:
['contains no lowercase X nor Y']

Input:
D = '1'; I = '3'; S = '3589841973169139975105820974944592078316406286208948254211370679314'
Output: ['58984197', '69', '9975105820974944592078', '64062862089482542', '', '70679', '4']

Input:
D = ' '; I = 'S'; S = 'regular split on spaces'
Output:
['regular', 'split', 'on', 'spaces']
\$\endgroup\$
6
  • \$\begingroup\$ Most (or all?) of the current answers do not have empty items at the beginning and end of test case 6. Is this a special case, or an error in the testcases? ("", "'ll remove all ", "") \$\endgroup\$
    – TFeld
    Oct 29, 2018 at 15:47
  • \$\begingroup\$ @TFeld It's a special case. Almost all answers also fail for D = ','; I = '"'; S = ',"a,b",c,,d,""' I just noticed. I'll modify the challenge a bit so empty items won't be possible at the start or end. Based on experience in both Java and 05AB1E in the past, I know how frustrating empty items after split can be to fix manually when the language doesn't do it correctly by default. A test cases like this should still be supported: D = ','; I = '"'; S = 'a,"b,c",d,,e['a', 'b,c', 'd', '', 'e'] with an empty item in between. \$\endgroup\$ Oct 29, 2018 at 15:57
  • \$\begingroup\$ Is it required that the final output maintain the order of the input? e.g. '1,"2,3"' -> ['2,3','1'] \$\endgroup\$ Oct 29, 2018 at 17:40
  • 1
    \$\begingroup\$ @KamilDrakari Hmm, I'll add a rule to allow it both forward and backward, but not shuffled. So [a,b,c] and [c,b,a] are allowed outputs, but [a,c,b] or [b,a,c] not for example. \$\endgroup\$ Oct 29, 2018 at 17:48
  • \$\begingroup\$ What should be the result of D=','; I='"'; S='a",b,"c' or is it even a valid input? \$\endgroup\$
    – Zgarb
    Oct 30, 2018 at 9:38

12 Answers 12

9
\$\begingroup\$

R, 34 bytes

Regular unmodified scan with the appropriate arguments for text, sep and quote should do it.

function(D,I,S)scan(,t=S,"",,,D,I)

Try it online!

\$\endgroup\$
7
  • 2
    \$\begingroup\$ As usual, R leading the way on string splitting challenges. \$\endgroup\$
    – ngm
    Oct 29, 2018 at 14:51
  • 2
    \$\begingroup\$ Talk about the right language for the job. :) Verified a few test cases, and they all seem to work fine, so +1 from me. PS: Taking input by storing it in a variable isn't allowed according to the meta. \$\endgroup\$ Oct 29, 2018 at 14:52
  • 1
    \$\begingroup\$ @KevinCruijssen Can I submit scan for 4 bytes and then call it with the arguments in the appropriate places? \$\endgroup\$
    – J.Doe
    Oct 29, 2018 at 15:16
  • 1
    \$\begingroup\$ @J.Doe Umm.. I dunno. Not too familiar with the possible acceptable input formats for R tbh. As far as I know using a full program with program arguments or STDIN, as well as a (lambda) function with the appropriate parameters or also using STDIN are acceptable by default. In the meta post I linked earlier all valid input-formats (with a positive score) are mentioned. How this works for R I don't know. \$\endgroup\$ Oct 29, 2018 at 15:37
  • \$\begingroup\$ @J.Doe your submission right now is a full program, and it currently does not take input from stdin. The shortest solution would be to wrap it into a function. \$\endgroup\$
    – Giuseppe
    Oct 29, 2018 at 15:41
7
\$\begingroup\$

C (gcc), 64 bytes

c;f(d,i,s)char*s;{for(;*s;s++)*s==i?c=!c:putchar(d-*s|c?*s:10);}

Try it online!

JavaScript (Node.js), 57 bytes

(d,i,s)=>s.replace(c=/./g,e=>i==e?(c^=1,''):d!=e|c?e:`
`)

Try it online!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Your C answer works great, but your JS answer seems to still split on D within I as well as contains I in the output, which can also be seen in the first test cases in your TIO link. (PS: It might also be better to post them as separated answers, with a link stating it's a port of your C answer.) \$\endgroup\$ Oct 29, 2018 at 16:04
  • 1
    \$\begingroup\$ @KevinCruijssen Fixed. Usually I post similar answers together, and only say it's a port if it's from others' work \$\endgroup\$
    – l4m2
    Oct 29, 2018 at 16:06
5
\$\begingroup\$

Pip, 18 bytes

FxcxQb?!:oOo?xRanx

Takes inputs as command-line arguments. Try it online!

Completely different approach: process the string one character at a time and output the desired results newline-delimited.

How?

                    a,b,c are cmdline args (respectively representing D,I,S); o is 1;
                    n is newline (implicit)
                    We use o for a flag indicating whether or not to change D into newline
Fxc                 For each character x in c:
   xQb?              If x equals b (the ignore character),
       !:o            Logically negate o in-place
          O          Else, output the following (with no trailing newline):
           o?         If o is truthy,
             xRan      x, with a (the delimiter) replaced with newline
                 x    Else, x unchanged
\$\endgroup\$
4
\$\begingroup\$

Python 2, 67 bytes

import csv
lambda D,I,S:next(csv.reader(S,delimiter=D,quotechar=I))

Try it online!

Python 2, 71 bytes

D,I,S=input()
k=1
for p in S.split(I):print p.replace(D*k,'\n'*k),;k^=1

Try it online!

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

MATL, 24 bytes

y=Yso~yi=*~*cO10Zt2G[]Zt

Inputs are S, I, D.

Try it online! Or verify all test cases.

How it works

Consider inputs D = ','; I = '"'; S = 'a,"b,c",d,,e,"",f'.

y     % Implicit inputs: S, I. Duplicate from below
      % STACK: 'a,"b,c",d,,e,"",f', '"', 'a,"b,c",d,,e,"",f'
=     % Is equal? Element-wise
      % STACK: 'a,"b,c",d,,e,"",f', [0 0 1 0 0 0 1 0 0 0 0 0 0 1 1 0 0]
Ys    % Cumulative sum
      % STACK: 'a,"b,c",d,,e,"",f', [0 0 1 1 1 1 2 2 2 2 2 2 2 3 4 4 4]
o~    % Parity, negate
      % STACK: 'a,"b,c",d,,e,"",f', [1 1 0 0 0 0 1 1 1 1 1 1 1 0 1 1 1]
y     % Duplicate from below
      % STACK: 'a,"b,c",d,,e,"",f', [1 1 0 0 0 0 1 1 1 1 1 1 1 0 1 1 1], 'a,"b,c",d,,e,"",f'
i=    % Input: D. Is equal? Element-wise
      % STACK: 'a,"b,c",d,,e,"",f', [1 1 0 0 0 0 1 1 1 1 1 1 1 0 1 1 1], [0 1 0 0 1 0 0 1 0 1 1 0 1 0 0 1 0]
*~    % Multiply, negate (equivalent to NAND). Element-wise
      % STACK: 'a,"b,c",d,,e,"",f', [1 0 1 1 1 1 1 0 1 0 0 1 0 1 1 0 1]
*     % Multiply, element-wise. Characters are converted to ASCII code
      % STACK: [97 0 34 98 44 99 34 0 100 0 0 101 0 34 34 0 102]
c     % Convert to char (character 0 is shown here as '·')
      % STACK: 'a·"b,c"·d··e·""·f'
O10   % Push 0 and then 10
      % STACK: 'a·"b,c"·d··e·""·f', 0, 10
Zt    % Replace character 0 by character 10 (newline; shown here as '¶')
      % STACK: 'a¶"b,c"¶d¶¶e¶""¶f'
2G[]  % Push second input (I) and then [] (empty array)
      % STACK: 'a¶"b,c"¶d¶¶e¶""¶f', '"', []
Zt    % Replace character given by input I by empty; that is, remove it. Implicit display
      % STACK: 'a¶b,c¶d¶¶e¶¶f'
\$\endgroup\$
3
\$\begingroup\$

Japt, 16 bytes

qV mÏu ?X:XrWRÃq

Try it!

Basically the same strategy as DLosc's newer Pip answer, sets aside the "quoted" sections then replaces the delimiter with a newline in the rest of the string, resulting in a newline delimited output

Full explanation:

qV                  Split on I
   m          Ã     For each segment:
    Ïu ?              If the segment has an odd index (quoted)...
        X             Keep it as-is
         :          Otherwise:
          XrWR        Replace each D in the segment with a newline
               q    Join it all to a single string

Note that even if the first item is quoted, it will still end up at index 1 not index 0. If q finds a delimiter as the first character, it makes the first item in the split (index 0) an empty string, so the contents of the quote correctly become the second item (index 1). Here is a demo of correctly dealing with a leading quote.

\$\endgroup\$
2
  • \$\begingroup\$ I just saved some bytes by replacing D with newline outside the quotes and splitting on newline, thereby removing the need to replace newline with D at the end. Could that shorten your code too? \$\endgroup\$
    – DLosc
    Oct 30, 2018 at 4:00
  • \$\begingroup\$ @DLosc Indeed, thanks for the suggestion! Putting in a new version now \$\endgroup\$ Oct 30, 2018 at 13:33
3
\$\begingroup\$

Retina, 45 bytes

L$`(?=.*¶(.)¶(.))(\2(.*?)\2|(.*?))(\1|¶)
$4$5

Try it online! Explanation:

(?=.*¶(.)¶(.))(\2(.*?)\2|(.*?))(\1|¶)

Look ahead to find the values of D and I on the following two lines. Then, if we find an I then eat it and match the characters to the next I and D, otherwise just match characters to the next D or the end of the line.

L$`
$4$5

List captures 4 and 5 from each match; 4 is the capture between two Is while 5 is the capture between two Ds.

\$\endgroup\$
3
\$\begingroup\$

Powershell, 71 bytes

param($d,$i,$s)$s-split{(1-($script:a+=$i-ceq$_)%2)*($d-ceq$_)}|% *m $i

Less golfed test script:

$f = {

param($d,$i,$s)
$s-split{
    $script:a+=$i-ceq$_
    (1-$a%2)-and($d-ceq$_)
}|% Trim $i

}

@(
    ,(',','"',
    '',
    '')

    ,(',','"',
    'a,"b,c",d,,e,"",f',
    'a', 'b,c', 'd', '', 'e', '', 'f')

    ,(',','"',
    '11020199,"Abc ",aduz,,444,bieb,dc,2 ,2222.00,whatever 5dc,222.22,22.00,"98,00","12,000,000",21-09-2018, 06:00,",-,"',
    '11020199', 'Abc ', 'aduz', '', '444', 'bieb', 'dc', '2 ', '2222.00', 'whatever 5dc', '222.22', '22.00', '98,00', '12,000,000', '21-09-2018', ' 06:00', ',-,')

    ,(' ',',',
    'this is a test , to see if you understand it, or not , hmmm, I think I have too many commas , or not , perhaps..',
    'this', 'is', 'a', 'test', ' to see if you understand it', 'or', 'not', ' hmmm', 'I', 'think', 'I', 'have', 'too', 'many', 'commas', ' or not ', 'perhaps..')

    ,('x','y',
    'contains no lowercase X nor Y',
    'contains no lowercase X nor Y')

    ,('1','3',
    '3589841973169139975105820974944592078316406286208948254211370679314',
    '58984197', '69', '9975105820974944592078', '64062862089482542', '', '70679', '4')

    ,(' ','S',
    'regular split on spaces',
    'regular', 'split', 'on', 'spaces')

) | % {
    $d,$i,$s,$expected = $_
    $result = &$f $d $i $s
    "$("$result"-eq"$expected"): $result"
}

Output:

True:
True: a b,c d  e  f
True: 11020199 Abc  aduz  444 bieb dc 2  2222.00 whatever 5dc 222.22 22.00 98,00 12,000,000 21-09-2018  06:00 ,-,
True: this is a test  to see if you understand it or not  hmmm I think I have too many commas  or not  perhaps..
True: contains no lowercase X nor Y
True: 58984197 69 9975105820974944592078 64062862089482542  70679 4
True: regular split on spaces

Explanation:

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

SNOBOL4 (CSNOBOL4), 109 bytes

	D =INPUT
	I =INPUT
	S =INPUT
S	S (I ARB . OUTPUT I | ARB . OUTPUT) (D | RPOS(0)) REM . S	DIFFER(S)	:S(S)
END

Try it online!

Suppose that D =',' and I ='"'. Then the pattern (I ARB . OUTPUT I | ARB . OUTPUT) (D | RPOS(0)) matches strings that look like ".*" or .* followed either by , or by the end of the string, and OUTPUTs the arbitrary (.*) characters, setting the unmatched REMainder to S and iterating so long as S is not empty.

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

Pip -n, 29 24 bytes

cR Xa[na]@(bN{$`})^n||:b

Takes inputs as command-line arguments. Try it online!

Strategy: outside I pairs, replace D with newline (since we're guaranteed that newlines won't appear in the string). Then split on newline and strip I.

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

Jelly,  20  18 bytes

;`j⁵œṣ⁴œṣḊṖYʋ€Ðo³Y

A full program taking the three arguments D, I, S which prints each item on a line.

Try it online! (Footer joins with newlines)

How?

Surround with an extra D on each side, split at Is, split the odd-indexed items at Ds then remove their heads and tails and join them with newlines, finally join the result with newlines.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ I think list output (as opposed to returning a list) needs to be delimited somehow, so you can tell 1) that it's a list at all, and 2) where one item ends and another begins. (I don't have a specific meta post to back that up, but there is a certain relatedness to the discussion on non-observable behavior. Right now, it's not observable that your program outputs a list rather than, say, a string.) \$\endgroup\$
    – DLosc
    Oct 30, 2018 at 4:11
  • \$\begingroup\$ So I guess I can replace the tighten with a join by newlines (which will return a list of lists of characters mixed with characters yet as a full program will print the items on new lines). \$\endgroup\$ Oct 30, 2018 at 7:22
  • \$\begingroup\$ ...so 17 with ;`j⁵œṣ⁴œṣḊṖɗ€Ðo³Y \$\endgroup\$ Oct 30, 2018 at 7:35
  • \$\begingroup\$ @JonathanAllan Your 20-byte solution works as intended, but your 17-byter in the comment seems to give some incorrect results. \$\endgroup\$ Oct 30, 2018 at 7:58
  • 1
    \$\begingroup\$ @KevinCruijssen - yep, mobile golf no good, I missed the join by newlines for the odd-indexed items, 18 posted. \$\endgroup\$ Oct 30, 2018 at 8:49
2
\$\begingroup\$

PHP, 50 bytes

function q($D,$I,$S){return str_getcsv($S,$D,$I);}

Try it online! Uses a built-in function.

If rearranging the inputs is allowed ((S,D,I) so it matches the str_getcsv signature), I have a 44 byte version.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ I believe that rearranging input is allowed, as long as you specify the order. To make it clearer, you can use the variables $S, $D and $I with a cost of 0 bytes, for this 50 byte long version. \$\endgroup\$ Oct 30, 2018 at 9:13
  • \$\begingroup\$ Also, the 50 bytes version, with the $S, $D, $I variables could serve as a guide for the order of the arguments. \$\endgroup\$ Oct 30, 2018 at 16:26

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.