Splitting text¶
One line: Splitting on a pattern looks like the simplest regex operation and disagrees across engines on three points — whether a captured delimiter comes back as a piece (Python, Perl, JavaScript, Ruby: yes; Java, Go, Rust: no), whether an empty pattern splits between every character or refuses, and how many empty pieces an edge produces — so a split that has to be portable uses a non-capturing pattern and strips its own empties.
Level: 201 · you have delimited text and want a list
What the driver asks¶
Every engine here was asked to split with "keep everything" semantics — Perl's -1 limit, Java's -1, Go's -1, Ruby's -1 — so the differences below are about the pattern, not about a limit argument. In your own code the defaults differ again: Perl and Ruby drop trailing empty pieces unless told not to; Java's String.split drops them too; Python, JavaScript, Go and Rust keep them.
Measured¶
Verified output of topic_splitting_text_sh.sh — regenerated by tools/run_examples.py, never hand-typed.
construct python perl node ruby java go rust fancy
plain delimiter [a,b,c] [a,b,c] [a,b,c] [a,b,c] [a,b,c] [a,b,c] [a,b,c] [a,b,c]
captured delimiter [a,;,b,;,c] [a,;,b,;,c] [a,;,b,;,c] [a,;,b,;,c] [a,b,c] [a,b,c] [a,b,c] [a,b,c]
trailing empty piece [a,b,] [a,b,] [a,b,] [a,b,] [a,b,] [a,b,] [a,b,] [a,b,]
leading empty piece [,a] [,a] [,a] [,a] [,a] [,a] [,a] [,a]
run of delimiters [a,b] [a,b] [a,b] [a,b] [a,b] [a,b] [a,b] [a,b]
on whitespace [a,b,c] [a,b,c] [a,b,c] [a,b,c] [a,b,c] [a,b,c] [a,b,c] [a,b,c]
zero-width split [a,ba,b] [a,ba,b] [a,ba,b] [a,ba,b] [a,ba,b] - - [a,ba,b]
split on every character [,a,b,c,] [a,b,c,] [a,b,c] [a,b,c,] [a,b,c,] [a,b,c] [,a,b,c,] [,a,b,c,]
Reading the table¶
- Rows 1, 3–6 are unanimous once the limit is set to keep everything: three pieces for
a;b;c, an empty trailing piece fora;b;, an empty leading piece for;a, one split for a run of delimiters when the pattern is;+, and whitespace runs as one delimiter. - Row 2, a captured delimiter.
(;)ona;b;c: Python, Perl, JavaScript and Ruby return five pieces — the delimiters are included,[a,;,b,;,c]. Java, Go and Rust return three — the capture is ignored. This is the most-ported split bug there is: code that relies on getting the delimiters back moves from Python to Go and silently loses them; code that does not expect them moves the other way and gets a list twice as long. - Row 7, a zero-width pattern.
(?=b)splits before eachbin the six engines that have lookahead —[a,ba,b]. Go and Rust refuse the lookahead, not the split. - Row 8, the empty pattern.
(?:)matches the empty string everywhere, and splitting on it produces four different answers:[,a,b,c,]with empties at both ends (Python, Rust),[a,b,c,]with one at the end (Perl, Ruby, Java), and[a,b,c]with none (JavaScript, Go). No engine refuses. The portable way to split into characters is not a regex.
The portable shape¶
split on (?:DELIM) — non-capturing, so no engine returns the delimiter
then drop empties — in the language, not by relying on the split's limit
If you want the delimiters back, and the engine is Java, Go or Rust, match instead: find every [^;]* or every [^;]+|; and sort the pieces in the loop. If you want them in Python or JavaScript, the capture does it — and now the code is not portable, which is worth a comment.
Keywords on this page¶
Capturing group · Non-capturing group · Lookahead · *, +, ? — the empty match again.
See also¶
- Extracting fields — usually the better tool when the pieces have structure.
- Portability between engines.