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\$
  • \$\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 '18 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\$ – Kevin Cruijssen Oct 29 '18 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\$ – Kamil Drakari Oct 29 '18 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\$ – Kevin Cruijssen Oct 29 '18 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 '18 at 9:38

12 Answers 12

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\$
  • \$\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 '18 at 4:00
  • \$\begingroup\$ @DLosc Indeed, thanks for the suggestion! Putting in a new version now \$\endgroup\$ – Kamil Drakari Oct 30 '18 at 13:33
8
\$\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\$
  • 2
    \$\begingroup\$ As usual, R leading the way on string splitting challenges. \$\endgroup\$ – ngm Oct 29 '18 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\$ – Kevin Cruijssen Oct 29 '18 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 '18 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\$ – Kevin Cruijssen Oct 29 '18 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 '18 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\$
  • 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\$ – Kevin Cruijssen Oct 29 '18 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 '18 at 16:06
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\$
4
\$\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\$

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

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\$
  • 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 '18 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\$ – Jonathan Allan Oct 30 '18 at 7:22
  • \$\begingroup\$ ...so 17 with ;`j⁵œṣ⁴œṣḊṖɗ€Ðo³Y \$\endgroup\$ – Jonathan Allan Oct 30 '18 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\$ – Kevin Cruijssen Oct 30 '18 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\$ – Jonathan Allan Oct 30 '18 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\$
  • 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\$ – Ismael Miguel Oct 30 '18 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\$ – Ismael Miguel Oct 30 '18 at 16:26

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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