splitter

Lazily splits a range using an element or range as a separator. Separator ranges can be any narrow string type or sliceable range type.

Two adjacent separators are considered to surround an empty element in the split range. Use filter!(a => !a.empty) on the result to compress empty elements.

The predicate is passed to std.functional.binaryFun and accepts any callable function that can be executed via pred(element, s).

Notes: If splitting a string on whitespace and token compression is desired, consider using splitter without specifying a separator.

If no separator is passed, the predicate isTerminator decides whether to accept an element of r.

  1. auto splitter(Range r, Separator s)
  2. auto splitter(Range r, Separator s)
  3. auto splitter(Range r)
    splitter
    (
    alias isTerminator
    Range
    )
    (
    Range r
    )
    if (
    isForwardRange!Range &&
    is(typeof(unaryFun!isTerminator(r.front)))
    )
  4. auto splitter(Range s)

Parameters

r Range

The input range to be split. Must support slicing and .length or be a narrow string type.

isTerminator

The predicate for deciding where to split the range when no separator is passed

Constraints: The predicate pred needs to accept an element of r and the separator s.

Return Value

Type: auto

An input range of the subranges of elements between separators. If r is a forward range or bidirectional range, the returned range will be likewise. When a range is used a separator, bidirectionality isn't possible.

If an empty range is given, the result is an empty range. If a range with one separator is given, the result is a range with two empty elements.

Examples

Basic splitting with characters and numbers.

import std.algorithm.comparison : equal;

assert("a|bc|def".splitter('|').equal([ "a", "bc", "def" ]));

int[] a = [1, 0, 2, 3, 0, 4, 5, 6];
int[][] w = [ [1], [2, 3], [4, 5, 6] ];
assert(a.splitter(0).equal(w));

Adjacent separators.

import std.algorithm.comparison : equal;

assert("|ab|".splitter('|').equal([ "", "ab", "" ]));
assert("ab".splitter('|').equal([ "ab" ]));

assert("a|b||c".splitter('|').equal([ "a", "b", "", "c" ]));
assert("hello  world".splitter(' ').equal([ "hello", "", "world" ]));

auto a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ];
auto w = [ [1, 2], [], [3], [4, 5], [] ];
assert(a.splitter(0).equal(w));

Empty and separator-only ranges.

import std.algorithm.comparison : equal;
import std.range : empty;

assert("".splitter('|').empty);
assert("|".splitter('|').equal([ "", "" ]));
assert("||".splitter('|').equal([ "", "", "" ]));

Use a range for splitting

1 import std.algorithm.comparison : equal;
2 
3 assert("a=>bc=>def".splitter("=>").equal([ "a", "bc", "def" ]));
4 assert("a|b||c".splitter("||").equal([ "a|b", "c" ]));
5 assert("hello  world".splitter("  ").equal([ "hello", "world" ]));
6 
7 int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ];
8 int[][] w = [ [1, 2], [3, 0, 4, 5, 0] ];
9 assert(a.splitter([0, 0]).equal(w));
10 
11 a = [ 0, 0 ];
12 assert(a.splitter([0, 0]).equal([ (int[]).init, (int[]).init ]));
13 
14 a = [ 0, 0, 1 ];
15 assert(a.splitter([0, 0]).equal([ [], [1] ]));

Custom predicate functions.

import std.algorithm.comparison : equal;
import std.ascii : toLower;

assert("abXcdxef".splitter!"a.toLower == b"('x').equal(
             [ "ab", "cd", "ef" ]));

auto w = [ [0], [1], [2] ];
assert(w.splitter!"a.front == b"(1).equal([ [[0]], [[2]] ]));

Use splitter without a separator

1 import std.algorithm.comparison : equal;
2 import std.range.primitives : front;
3 
4 assert(equal(splitter!(a => a == '|')("a|bc|def"), [ "a", "bc", "def" ]));
5 assert(equal(splitter!(a => a == ' ')("hello  world"), [ "hello", "", "world" ]));
6 
7 int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ];
8 int[][] w = [ [1, 2], [], [3], [4, 5], [] ];
9 assert(equal(splitter!(a => a == 0)(a), w));
10 
11 a = [ 0 ];
12 assert(equal(splitter!(a => a == 0)(a), [ (int[]).init, (int[]).init ]));
13 
14 a = [ 0, 1 ];
15 assert(equal(splitter!(a => a == 0)(a), [ [], [1] ]));
16 
17 w = [ [0], [1], [2] ];
18 assert(equal(splitter!(a => a.front == 1)(w), [ [[0]], [[2]] ]));

Leading separators, trailing separators, or no separators.

import std.algorithm.comparison : equal;

assert("|ab|".splitter('|').equal([ "", "ab", "" ]));
assert("ab".splitter('|').equal([ "ab" ]));

Splitter returns bidirectional ranges if the delimiter is a single element

import std.algorithm.comparison : equal;
import std.range : retro;
assert("a|bc|def".splitter('|').retro.equal([ "def", "bc", "a" ]));

Splitting by word lazily

import std.ascii : isWhite;
import std.algorithm.comparison : equal;
import std.algorithm.iteration : splitter;

string str = "Hello World!";
assert(str.splitter!(isWhite).equal(["Hello", "World!"]));

See Also

std.regex._splitter for a version that splits using a regular expression defined separator and std.array._split for a version that splits eagerly.

Meta

Suggestion Box / Bug Report