The OpenD Programming Language

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)
    splitter
    (
    alias pred = "a == b"
    Flag!"keepSeparators" keepSeparators = No.keepSeparators
    Range
    Separator
    )
    (
    Range r
    ,
    Separator s
    )
    if (
    is(typeof(binaryFun!pred(r.front, s)) : bool) &&
    (
    (
    hasSlicing!Range &&
    hasLength!Range
    )
    ||
    )
    )
  2. auto splitter(Range r, Separator s)
  3. auto splitter(Range r)
  4. auto splitter(Range s)

Parameters

pred

The predicate for comparing each element with the separator, defaulting to "a == b".

r Range

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

s Separator

The element (or range) to be treated as the separator between range segments to be split.

keepSeparators

The flag for deciding if the separators are kept

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 keepSeparators is equal to Yes.keepSeparators the output will also contain the separators.

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));

Basic splitting with characters and numbers and keeping sentinels.

import std.algorithm.comparison : equal;
import std.typecons : Yes;

assert("a|bc|def".splitter!("a == b", Yes.keepSeparators)('|')
    .equal([ "a", "|", "bc", "|", "def" ]));

int[] a = [1, 0, 2, 3, 0, 4, 5, 6];
int[][] w = [ [1], [0], [2, 3], [0], [4, 5, 6] ];
assert(a.splitter!("a == b", Yes.keepSeparators)(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));

Adjacent separators and keeping sentinels.

import std.algorithm.comparison : equal;
import std.typecons : Yes;

assert("|ab|".splitter!("a == b", Yes.keepSeparators)('|')
    .equal([ "", "|", "ab", "|", "" ]));
assert("ab".splitter!("a == b", Yes.keepSeparators)('|')
    .equal([ "ab" ]));

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

auto a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ];
auto w = [ [1, 2], [0], [], [0], [3], [0], [4, 5], [0], [] ];
assert(a.splitter!("a == b", Yes.keepSeparators)(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([ "", "", "" ]));

Empty and separator-only ranges and keeping sentinels.

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

assert("".splitter!("a == b", Yes.keepSeparators)('|').empty);
assert("|".splitter!("a == b", Yes.keepSeparators)('|')
    .equal([ "", "|", "" ]));
assert("||".splitter!("a == b", Yes.keepSeparators)('|')
    .equal([ "", "|", "", "|", "" ]));

Use a range for splitting

import std.algorithm.comparison : equal;

assert("a=>bc=>def".splitter("=>").equal([ "a", "bc", "def" ]));
assert("a|b||c".splitter("||").equal([ "a|b", "c" ]));
assert("hello  world".splitter("  ").equal([ "hello", "world" ]));

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

a = [ 0, 0 ];
assert(a.splitter([0, 0]).equal([ (int[]).init, (int[]).init ]));

a = [ 0, 0, 1 ];
assert(a.splitter([0, 0]).equal([ [], [1] ]));

Use a range for splitting

import std.algorithm.comparison : equal;
import std.typecons : Yes;

assert("a=>bc=>def".splitter!("a == b", Yes.keepSeparators)("=>")
    .equal([ "a", "=>", "bc", "=>", "def" ]));
assert("a|b||c".splitter!("a == b", Yes.keepSeparators)("||")
    .equal([ "a|b", "||", "c" ]));
assert("hello  world".splitter!("a == b", Yes.keepSeparators)("  ")
    .equal([ "hello", "  ",  "world" ]));

int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ];
int[][] w = [ [1, 2], [0, 0], [3, 0, 4, 5, 0] ];
assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0]).equal(w));

a = [ 0, 0 ];
assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0])
    .equal([ (int[]).init, [0, 0], (int[]).init ]));

a = [ 0, 0, 1 ];
assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0])
    .equal([ [], [0, 0], [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]] ]));

Custom predicate functions.

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

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

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

Use splitter without a separator

import std.algorithm.comparison : equal;
import std.range.primitives : front;

assert(equal(splitter!(a => a == '|')("a|bc|def"), [ "a", "bc", "def" ]));
assert(equal(splitter!(a => a == ' ')("hello  world"), [ "hello", "", "world" ]));

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

a = [ 0 ];
assert(equal(splitter!(a => a == 0)(a), [ (int[]).init, (int[]).init ]));

a = [ 0, 1 ];
assert(equal(splitter!(a => a == 0)(a), [ [], [1] ]));

w = [ [0], [1], [2] ];
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" ]));

Leading separators, trailing separators, or no separators.

import std.algorithm.comparison : equal;
import std.typecons : Yes;

assert("|ab|".splitter!("a == b", Yes.keepSeparators)('|')
    .equal([ "", "|", "ab", "|", "" ]));
assert("ab".splitter!("a == b", Yes.keepSeparators)('|')
    .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" ]));

Splitter returns bidirectional ranges if the delimiter is a single element

import std.algorithm.comparison : equal;
import std.typecons : Yes;
import std.range : retro;
assert("a|bc|def".splitter!("a == b", Yes.keepSeparators)('|')
    .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, std.array._split for a version that splits eagerly and splitWhen, which compares adjacent elements instead of element against separator.

Meta