Multisplit: Difference between revisions

20,208 bytes added ,  21 days ago
Added Easylang
m (→‎{{header|Haskell}}: preferred `maybe` to `case Just ... Nothing ...` in fold version.)
(Added Easylang)
 
(31 intermediate revisions by 19 users not shown)
Line 24:
 
'''Extra Credit:''' provide information that indicates which separator was matched at each separation point and where in the input string that separator was matched.
 
=={{header|11l}}==
{{trans|Python}}
 
<syntaxhighlight lang="11l">F multisplit(text, sep)
V lastmatch = 0
V i = 0
V matches = ‘’
L i < text.len
L(s) sep
V j = L.index
I text[i..].starts_with(s)
I i > lastmatch
matches ‘’= text[lastmatch .< i]
matches ‘’= ‘{’s‘}’
lastmatch = i + s.len
i += s.len
L.break
L.was_no_break
i++
I i > lastmatch
matches ‘’= text[lastmatch .< i]
R matches
 
print(multisplit(‘a!===b=!=c’, [‘==’, ‘!=’, ‘=’]))</syntaxhighlight>
 
{{out}}
<pre>
a{!=}{==}b{=}{!=}c
</pre>
 
=={{header|Ada}}==
multisplit.adb:
<langsyntaxhighlight Adalang="ada">with Ada.Containers.Indefinite_Doubly_Linked_Lists;
with Ada.Text_IO;
 
Line 107 ⟶ 137:
Pos := String_Lists.Next (Pos);
end loop;
end Multisplit;</langsyntaxhighlight>
 
{{out}}
Line 114 ⟶ 144:
 
=={{header|ALGOL 68}}==
<langsyntaxhighlight lang="algol68"># split a string based on a number of separators #
 
# MODE to hold the split results #
Line 179 ⟶ 209:
SPLITINFO token = test tokens[ t ];
print( ( "token: [", text OF token, "] at: ", whole( position OF token, 0 ), " delimiter: (", delimiter OF token, ")", newline ) )
OD</langsyntaxhighlight>
{{out}}
<pre>
Line 188 ⟶ 218:
token: [c] at: 10 delimiter: ()
</pre>
 
=={{header|Arturo}}==
 
<syntaxhighlight lang="rebol">print split.by:["==" "!=" "="] "a!===b=!=c"</syntaxhighlight>
 
{{out}}
 
<pre>a b c</pre>
 
=={{header|AutoHotkey}}==
<langsyntaxhighlight AutoHotkeylang="autohotkey">Str := "a!===b=!=c"
Sep := ["==","!=", "="]
Res := StrSplit(Str, Sep)
Line 198 ⟶ 236:
for k, v in Sep
N .= (N?"|":"") "\Q" v "\E"
MsgBox % RegExReplace(str, "(.*?)(" N ")", "$1 {$2}")</langsyntaxhighlight>
{{out}}
<pre>a,,b,,c
Line 204 ⟶ 242:
 
=={{header|AWK}}==
<syntaxhighlight lang="awk">
<lang AWK>
# syntax: GAWK -f MULTISPLIT.AWK
BEGIN {
Line 228 ⟶ 266:
exit(0)
}
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 240 ⟶ 278:
separators: '!=' '==' '=' '!='
</pre>
 
=={{header|BBC BASIC}}==
<langsyntaxhighlight lang="bbcbasic"> DIM sep$(2)
sep$() = "==", "!=", "="
PRINT "String splits into:"
Line 264 ⟶ 303:
ENDIF
UNTIL m% = LEN(s$)
= o$ + """" + MID$(s$, p%) + """"</langsyntaxhighlight>
{{out}}
<pre>
Line 275 ⟶ 314:
=={{header|Bracmat}}==
This is a surprisingly difficult task to solve in Bracmat, because in a naive solution using a alternating pattern ("=="|"!="|"=") the shorter pattern <code>"="</code> would have precedence over <code>"=="</code>. In the solution below the function <code>oneOf</code> iterates (by recursion) over the operators, trying to match the start of the current subject string <code>sjt</code> with one operator at a time, until success or reaching the end of the list with operators, whichever comes first. If no operator is found at the start of the current subject string, the variable <code>nonOp</code> is extended with one byte, thereby shifting the start of the current subject string one byte to the right. Then a new attempt is made to find an operator. This is repeated until either an operator is found, in which case the unparsed string is restricted to the part of the input after the found operator, or no operator is found, in which case the <code>whl</code> loop terminates.
<langsyntaxhighlight lang="bracmat">( ( oneOf
= operator
. !arg:%?operator ?arg
Line 292 ⟶ 331:
& put$!unparsed
& put$\n
);</langsyntaxhighlight>
{{out}}
<pre>a {!=} {==} b {=} {!=} c</pre>
Line 298 ⟶ 337:
=={{header|C}}==
What kind of silly parsing is this?
<langsyntaxhighlight Clang="c">#include <stdio.h>
#include <string.h>
 
Line 321 ⟶ 360:
 
return 0;
}</langsyntaxhighlight>
{{out}}<syntaxhighlight lang="text">a{!=}{==}b{=}{!=}c</langsyntaxhighlight>
 
=={{header|C++}}==
using the Boost library tokenizer!
<lang cpp>#include <iostream>
#include <boost/tokenizer.hpp>
#include <string>
 
int main( ) {
std::string str( "a!===b=!=c" ) , output ;
typedef boost::tokenizer<boost::char_separator<char> > tokenizer ;
boost::char_separator<char> separator ( "==" , "!=" ) , sep ( "!" ) ;
tokenizer mytok( str , separator ) ;
tokenizer::iterator tok_iter = mytok.begin( ) ;
for ( ; tok_iter != mytok.end( ) ; ++tok_iter )
output.append( *tok_iter ) ;
tokenizer nexttok ( output , sep ) ;
for ( tok_iter = nexttok.begin( ) ; tok_iter != nexttok.end( ) ;
++tok_iter )
std::cout << *tok_iter << " " ;
std::cout << '\n' ;
return 0 ;
}</lang>
{{out}}
<PRE>a b c</PRE>
 
=={{header|C sharp}}==
Line 352 ⟶ 367:
'''Extra Credit Solution'''
 
<langsyntaxhighlight lang="csharp">using System;
using System.Collections.Generic;
using System.Linq;
Line 408 ⟶ 423:
}
}
}</langsyntaxhighlight>
 
{{out}}
<pre>a{"!=", (1, 3)}{"==", (3, 5)}b{"=", (6, 7)}{"!=", (7, 9)}c
</pre>
 
=={{header|C++}}==
using the Boost library tokenizer!
<syntaxhighlight lang="cpp">#include <iostream>
#include <boost/tokenizer.hpp>
#include <string>
 
int main( ) {
std::string str( "a!===b=!=c" ) , output ;
typedef boost::tokenizer<boost::char_separator<char> > tokenizer ;
boost::char_separator<char> separator ( "==" , "!=" ) , sep ( "!" ) ;
tokenizer mytok( str , separator ) ;
tokenizer::iterator tok_iter = mytok.begin( ) ;
for ( ; tok_iter != mytok.end( ) ; ++tok_iter )
output.append( *tok_iter ) ;
tokenizer nexttok ( output , sep ) ;
for ( tok_iter = nexttok.begin( ) ; tok_iter != nexttok.end( ) ;
++tok_iter )
std::cout << *tok_iter << " " ;
std::cout << '\n' ;
return 0 ;
}</syntaxhighlight>
{{out}}
<PRE>a b c</PRE>
 
===Without external libraries===
<syntaxhighlight lang="c++">
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>
 
struct Split_data {
std::string segment;
int32_t index;
std::string separator;
};
 
std::vector<Split_data> multi_split(const std::string& text, const std::vector<std::string>& separators) {
std::vector<Split_data> result;
uint64_t i = 0;
std::string segment = "";
while ( i < text.length() ) {
bool found = false;
for ( std::string separator : separators ) {
if ( text.substr(i, separator.length()) == separator ) {
found = true;
result.emplace_back(segment, i, separator);
i += separator.length();
segment = "";
break;
}
}
 
if ( ! found ) {
segment += text[i];
i += 1;
}
}
result.emplace_back(segment, i, "");
return result;
}
 
int main() {
for ( Split_data splits : multi_split("a!===b=!=c", { "==", "!=", "=" } ) ) {
std::cout << std::left << std::setw(3) << "\"" + splits.segment + "\""
<< std::setw(18) << " ( split with \"" + splits.separator + "\""
<< " at index " << splits.index << " )" << std::endl;
}
}
</syntaxhighlight>
{{ out }}
<pre>
"a" ( split with "!=" at index 1 )
"" ( split with "==" at index 3 )
"b" ( split with "=" at index 6 )
"" ( split with "!=" at index 7 )
"c" ( split with "" at index 10 )
</pre>
 
 
===C++23===
<syntaxhighlight lang="c++">
/* multisplit.cpp */
#include <features.h>
#include <iostream>
#include <string>
#include <vector>
#include <format>
 
/* C++23 example for Multisplit 6 Jan 2024
email:
spikeysnack@gmail.com
 
compile:
g++-13 -std=c++23 -Wall -o multisplit multisplit.cpp
*/
 
// extra info
#define _EXTRA
 
// aliases
using std::string;
using std::vector;
using str_vec = vector<string>;
using std::cout;
 
 
// constants
constexpr static const size_t npos = -1;
 
// function signatures
string replace_all(string& str, string& remove, string& insert );
 
str_vec split_on_delim(string& str, const string& delims);
 
str_vec Multisplit( string& input, const str_vec& seps);
 
// functions
 
// replace all substrings in string
// a = "dogs and cats and dogs and cats and birds"
// replace(a, "cats" , "fish");
// ==> "dogs and fish and dogs and fish and birds"
 
string replace_all(string& str,
const string& remove,
const string& insert ){
string s{str};
string::size_type pos = 0;
 
#ifdef _EXTRA
const string rightarrow{"\u2B62"}; //unicode arrow
auto ex = std::format("match: {}\t{} ", remove, rightarrow);
std::cerr << ex;
#endif
while ((pos = s.find(remove, pos)) != npos){
s.replace(pos, remove.size(), insert);
pos++;
}
 
return s;
}
 
 
// create a string vector from a string,
// split on a delimiter string
// x = "ab:cde:fgh:ijk"
// split_on_delim( x, ":");
// ==> { "ab", "cde", "fgh", "ijk" }
 
str_vec split_on_delim(string& str, const string& delims) {
string::size_type beg, pos = 0;
str_vec sv;
string tmp;
while ( (beg = str.find_first_not_of(delims, pos)) != npos ){
 
pos = str.find_first_of(delims, beg + 1);
 
tmp = { str.substr(beg, pos - beg) };
 
sv.push_back(tmp);
}
return sv;
}
 
 
str_vec Multisplit( string& input, const str_vec& seps) {
 
string s1{input};
str_vec sv;
 
for( auto sep : seps){
s1 = replace_all(s1, sep, "^"); // space sep
 
#ifdef _EXTRA
std::cerr << s1 << "\n";
#endif
sv = split_on_delim(s1, "^"); // split
}
return sv;
}
 
 
/* main program */
 
int main(){
string sample{"a!===b=!=c"};
 
const str_vec seps {"!=", "==", "="};
 
auto s = std::format("sample: \t{}\n", sample);
 
cout << s;
 
auto sv = Multisplit(sample, seps);
 
for( auto s : sv){
auto out = std::format( "{}\t" , s);
cout << out;
}
cout << "\n";
return 0;
}
 
// end
</syntaxhighlight>
 
{{ out }}
<pre>
sample: a!===b=!=c
match: != ⭢ a^==b=^c
match: == ⭢ a^^b=^c
match: = ⭢ a^^b^^c
a b c
 
</pre>
 
=={{header|CoffeeScript}}==
<langsyntaxhighlight lang="coffeescript">
multi_split = (text, separators) ->
# Split text up, using separators to break up text and discarding
Line 446 ⟶ 683:
console.log multi_split 'a!===b=!=c', ['==', '!=', '='] # [ 'a', '', 'b', '', 'c' ]
console.log multi_split '', ['whatever'] # [ '' ]
</syntaxhighlight>
</lang>
 
=={{header|D}}==
<langsyntaxhighlight lang="d">import std.stdio, std.array, std.algorithm;
 
string[] multiSplit(in string s, in string[] divisors) pure nothrow {
Line 486 ⟶ 723:
.join(" {} ")
.writeln;
}</langsyntaxhighlight>
{{out}} (separator locations indicated by braces):
<pre>a {} {} b {} {} c</pre>
=={{header|Delphi}}==
{{libheader| System.SysUtils}}
<syntaxhighlight lang="delphi">
program Multisplit;
 
{$APPTYPE CONSOLE}
 
uses
System.SysUtils;
 
begin
write('[');
for var s in 'a!===b=!=c'.Split(['==', '!=', '=']) do
write(s.QuotedString('"'), ' ');
write(']');
readln;
end.</syntaxhighlight>
{{out}}
<pre>["a" "" "b" "" "c" ]</pre>
=={{header|EasyLang}}==
<syntaxhighlight>
proc multisplit str$ sep$[] . .
repeat
min = 1 / 0
for sep$ in sep$[]
pos = strpos str$ sep$
if pos > 0 and pos < min
min = pos
msep$ = sep$
.
.
until min = 1 / 0
write substr str$ 1 (min - 1) & "{" & msep$ & "}"
str$ = substr str$ (min + len msep$) 9999
.
print str$
.
multisplit "a!===b=!=c" [ "==" "!=" "=" ]
</syntaxhighlight>
{{out}}
<pre>
a{!=}{==}b{=}{!=}c
</pre>
 
=={{header|Elixir}}==
{{trans|Erlang}}
<langsyntaxhighlight lang="elixir">iex(1)> Regex.split(~r/==|!=|=/, "a!====b=!=c")
["a", "", "", "b", "", "c"]</langsyntaxhighlight>
 
=={{header|Erlang}}==
Line 500 ⟶ 780:
["a",[],"b",[],"c"]
</pre>
 
 
=={{header|F_Sharp|F#}}==
 
If we ignore the "Extra Credit" requirements and skip 'ordered separators' condition (i.e. solving absolute different task), this is exactly what one of the overloads of .NET's <code>String.Split</code> method does. Using F# Interactive:
<syntaxhighlight lang="fsharp">> "a!===b=!=c".Split([|"=="; "!="; "="|], System.StringSplitOptions.None);;
val it : string [] = [|"a"; ""; "b"; ""; "c"|]
 
> "a!===b=!=c".Split([|"="; "!="; "=="|], System.StringSplitOptions.None);;
val it : string [] = [|"a"; ""; ""; "b"; ""; "c"|]</syntaxhighlight>
 
<code>System.StringSplitOptions.None</code> specifies that empty strings should be included in the result.
 
=={{header|Factor}}==
<syntaxhighlight lang="factor">USING: arrays fry kernel make sequences ;
 
IN: rosetta-code.multisplit
 
: first-subseq ( seq separators -- n separator )
tuck
[ [ subseq-index ] dip 2array ] withd map-index sift-keys
[ drop f f ] [ [ first ] infimum-by first2 rot nth ] if-empty ;
 
: multisplit ( string separators -- seq )
'[
[ dup _ first-subseq dup ] [
length -rot cut-slice [ , ] dip swap tail-slice
] while 2drop ,
] { } make ;</syntaxhighlight>
 
{{out}}
<pre>> "a!===b=!=c" { "==" "!=" "=" } multisplit [ >string ] map .
 
{ "a" "" "b" "" "c" }</pre>
 
=={{header|FreeBASIC}}==
FreeBASIC does not have a built in 'split' function so we need to write one:
<langsyntaxhighlight lang="freebasic">' FB 1.05.0 Win64
 
Sub Split(s As String, sepList() As String, result() As String, removeEmpty As Boolean = False, showSepInfo As Boolean = False)
Line 576 ⟶ 890:
Print
Print "Press any key to quit"
Sleep</langsyntaxhighlight>
 
{{out}}
Line 595 ⟶ 909:
5 : c
</pre>
 
=={{header|F_Sharp|F#}}==
 
If we ignore the "Extra Credit" requirements and skip 'ordered separators' condition (i.e. solving absolute different task), this is exactly what one of the overloads of .NET's <code>String.Split</code> method does. Using F# Interactive:
<lang fsharp>> "a!===b=!=c".Split([|"=="; "!="; "="|], System.StringSplitOptions.None);;
val it : string [] = [|"a"; ""; "b"; ""; "c"|]
 
> "a!===b=!=c".Split([|"="; "!="; "=="|], System.StringSplitOptions.None);;
val it : string [] = [|"a"; ""; ""; "b"; ""; "c"|]</lang>
 
<code>System.StringSplitOptions.None</code> specifies that empty strings should be included in the result.
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import (
Line 633 ⟶ 936:
func main() {
fmt.Printf("%q\n", ms("a!===b=!=c", []string{"==", "!=", "="}))
}</langsyntaxhighlight>
{{out}}
<pre>
Line 640 ⟶ 943:
 
=={{header|Haskell}}==
<langsyntaxhighlight Haskelllang="haskell">import Data.List
(isPrefixOf, stripPrefix, genericLength, intercalate)
intercalate,
isPrefixOf,
stripPrefix,
)
------------------------ MULTISPLIT ----------------------
 
trysplitmultisplit :: [String] -> [String] -> Maybe [(String, String, Int)]
trysplit smultisplit delims = go [] 0
where
go acc pos [] = [(acc, [], pos)]
go acc pos l@(s : sx) =
case trysplit delims l of
Nothing -> go (s : acc) (pos + 1) sx
Just (d, sxx) ->
(acc, d, pos) :
go [] (pos + genericLength d) sxx
 
trysplit :: [String] -> String -> Maybe (String, String)
trysplit delims s =
case filter (`isPrefixOf` s) delims of
[] -> Nothing
(d : _) -> Just (d, (\(Just x) -> x) $ stripPrefix d s)
 
multisplit :: String -> [String] -> [(String, String, Int)]
multisplit list delims =
let ms [] acc pos = [(acc, [], pos)]
ms l@(s:sx) acc pos =
case trysplit l delims of
Nothing -> ms sx (s : acc) (pos + 1)
Just (d, sxx) -> (acc, d, pos) : ms sxx [] (pos + genericLength d)
in ms list [] 0
 
--------------------------- TEST -------------------------
main :: IO ()
main = do
let parsed = multisplit "a!===b=!=c" ["==", "!=", "="] "a!===b=!=c"
mapM_
putStrLn
[ "split string:",
, intercalate "," $ map (\(a, _, _) -> a) parsed,
, "with [(string, delimiter, offset)]:",
, show parsed
]</langsyntaxhighlight>
{{out}}
<pre>split string:
Line 676 ⟶ 988:
Or as a fold:
 
<langsyntaxhighlight lang="haskell">import Data.List (find, isPrefixOf, foldl') --'
import Data.Bool (bool)
 
Line 693 ⟶ 1,005:
in reverse $ (ts, [], length s) : ps
main :: IO ()
main = print $ multiSplit ["==", "!=", "="] "a!===b=!=c"</langsyntaxhighlight>
{{Out}}
<pre>[("a","!=",1),("","==",3),("b","=",6),("","!=",7),("c","",10)]</pre>
 
=={{header|Icon}} and {{header|Unicon}}==
<langsyntaxhighlight Iconlang="icon">procedure main()
s := "a!===b=!=c"
# just list the tokens
Line 718 ⟶ 1,030:
procedure arb()
suspend .&subject[.&pos:&pos <- &pos to *&subject + 1]
end</langsyntaxhighlight>
 
{{out}}
Line 725 ⟶ 1,037:
 
=={{header|J}}==
<syntaxhighlight lang ="j">multisplit=: 4 :0{{
'sep begin sep'=. |: tbs=. y _,~/:~;(,.&.:(|."1)@;@(>i.@#@[) ,.L:0"0y I.@E.L:0) x NB.
endlen=. begin + sep { #@>y NB.
lastr=. next=i.3 0
rj=. 2k=. 0$0
while. nextj<#beginx do.
while. j>k{begin do. k=.k+1 end.
r=. r,.(last}.x{.~next{begin);next{t
'b s'=. k{bs NB. character index where separator appears, separator index
last=. next{end
if. _=b do. r,.(j}.x);'';'' return. end.
next=. 1 i.~(begin>next{begin)*.begin>:last
txt=. (j + i. b-j){x
j=. b+s{len
r=.r,.txt;(s{::y);b
end.
}}</syntaxhighlight>
r=. r,.'';~last}.x
)</lang>
 
Explanation:
 
First find all potentially relevant separator instances, and sort them in increasing order, by starting location and separator index. <code>sep</code> is separator index, and <code>begin</code> is starting location. <code>end</code> is ending location.
 
Then, loop through the possibilities, skipping over those separators which would overlap with previously used separators.
 
The result consists of twothree rows: The first row is the extracted substrings, the second rowand isthird rows are the "extra credit" part -- for each extracted substring, the numbers in the second row are the separator index for: the following separator (0 for the first separator, 1 for the second, ...), and the locationposition in the original string where the beginning of thethat separator appeared (which is the same as where the end of the extracted substring appeared)started. Note that the very last substring does not have a separator following it, so the extra credit part is blank for that substring.
 
Example use:
 
<langsyntaxhighlight lang="j"> S=: multisplit 'a!===b=';'!=c';'='
┌──┬──┬─┬──┬─┐
S multisplit '==';'!=';'='
│a │ │b│ │c│
┌───┬───┬───┬───┬─┐
├──┼──┼─┼──┼─┤
│a │ │b │ │c│
│!=│==│=│!=│ │
├───┼───┼───┼───┼─┤
├──┼──┼─┼──┼─┤
│1 1│0 3│2 6│1 7│ │
│1 │3 │6│7 │ │
└───┴───┴───┴───┴─┘
└──┴──┴─┴──┴─┘
S multisplit '=';'!=';'=='
┌──┬─┬─┬─┬──┬─┐
┌───┬───┬───┬───┬───┬─┐
│a │ │b │b│ │c│
├──┼─┼─┼─┼──┼─┤
├───┼───┼───┼───┼───┼─┤
│!=│=│=│=│!=│ │
│1 1│0 3│0 4│0 6│1 7│ │
├──┼─┼─┼─┼──┼─┤
└───┴───┴───┴───┴───┴─┘
│1 │3│4│6│7 │ │
└──┴─┴─┴─┴──┴─┘
'X123Y' multisplit '1';'12';'123';'23';'3'
┌─┬──┬─┐
┌───┬───┬─┐
│X │ │X│ │Y│
├─┼──┼─┤
├───┼───┼─┤
│0 1│3 2││1│23│
├─┼──┼─┤
└───┴───┴─┘</lang>
│1│2 │ │
└─┴──┴─┘</syntaxhighlight>
 
=={{header|Java}}==
<langsyntaxhighlight lang="java">import java.util.*;
 
public class MultiSplit {
Line 801 ⟶ 1,120:
return result;
}
}</langsyntaxhighlight>
 
<pre>Regex split:
Line 813 ⟶ 1,132:
Based on Ruby example.
{{libheader|Underscore.js}}
<langsyntaxhighlight JavaScriptlang="javascript">RegExp.escape = function(text) {
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
}
Line 820 ⟶ 1,139:
var sep_regex = RegExp(_.map(seps, function(sep) { return RegExp.escape(sep); }).join('|'));
return string.split(sep_regex);
}</langsyntaxhighlight>
 
===ES6===
Line 826 ⟶ 1,145:
 
{{Trans|Haskell}} (Multisplit by fold example)
<langsyntaxhighlight lang="javascript">(() => {
 
/// Delimiter list -> String -> list of parts, delimiters, offsets
Line 944 ⟶ 1,263:
multiSplit(delims, strTest)
);
})();</langsyntaxhighlight>
{{Out}}
<pre>[
Line 982 ⟶ 1,301:
Both helper functions could be made inner functions of the main function, but are kept separate here for clarity.
 
<langsyntaxhighlight lang="jq"># peeloff(delims) either peels off a delimiter or
# a single character from the input string.
# The input should be a nonempty string, and delims should be
Line 1,028 ⟶ 1,347:
then .[0:length-1] + [ .[length-1] + $x ]
else . + [$x]
end ) ;</langsyntaxhighlight>
'''Examples'''
("a!===b=!=c",
Line 1,039 ⟶ 1,358:
=={{header|Julia}}==
From REPL:
<langsyntaxhighlight lang="julia">
julia> split(s, r"==|!=|=")
5-element Array{SubString{String},1}:
Line 1,047 ⟶ 1,366:
""
"c"
</syntaxhighlight>
</lang>
 
 
=={{header|Kotlin}}==
<langsyntaxhighlight lang="scala">// version 1.0.6
 
fun main(args: Array<String>) {
Line 1,081 ⟶ 1,399:
println("\nThe delimiters matched and the indices at which they occur are:")
println(matches)
}</langsyntaxhighlight>
 
{{out}}
Line 1,094 ⟶ 1,412:
=={{header|Lua}}==
The function I've written here is really excessive for this task but it has historically been hard to find example code for a good Lua split function on the Internet. This one behaves the same way as Julia's Base.split and I've included a comment describing its precise operation.
<langsyntaxhighlight Lualang="lua">--[[
Returns a table of substrings by splitting the given string on
occurrences of the given character delimiters, which may be specified
Line 1,146 ⟶ 1,464:
for k, v in pairs(multisplit) do
print(k, v)
end</langsyntaxhighlight>
{{Out}}
<pre>Key Value
Line 1,159 ⟶ 1,477:
Code from BBC BASIC with little changes to fit in M2000.
 
<syntaxhighlight lang="m2000 interpreter">
<lang M2000 Interpreter>
Module CheckIt {
DIM sep$()
Line 1,189 ⟶ 1,507:
}
CheckIt
</syntaxhighlight>
</lang>
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
 
=={{header|Mathematica}}==
Just use the built-in function "StringSplit":
<langsyntaxhighlight lang="mathematica">StringSplit["a!===b=!=c", {"==", "!=", "="}]</langsyntaxhighlight>
{{Out}}
<pre>{a,,b,,c}</pre>
 
=={{header|MiniScript}}==
<langsyntaxhighlight MiniScriptlang="miniscript">parseSep = function(s, pats)
result = []
startPos = 0
Line 1,217 ⟶ 1,534:
end function
 
print parseSep("a!===b=!=c", ["==", "!=", "="])</langsyntaxhighlight>
{{Out}}
<pre>["a", "{!=}", "", "{==}", "b", "{=}", "", "{!=}"]</pre>
 
 
 
=={{header|Nim}}==
<langsyntaxhighlight lang="nim">import strutils
 
iterator tokenize(text,: string; sep: openArray[string]): tuple[token: string, isSep: bool] =
var i, lastMatch = 0
while i < text.len:
for j, s in sep:
if text[i..text.high].startsWith s:
if i > lastMatch: yield (text[lastMatch .. < i], false)
yield (s, true)
lastMatch = i + s.len
Line 1,237 ⟶ 1,552:
break
inc i
if i > lastMatch: yield (text[lastMatch .. < i], false)
 
for token, isSep in "a!===b=!=c".tokenize(["==", "!=", "="]):
if isSep: stdout.write '{',token,'}'
else: stdout.write token
echo ""</langsyntaxhighlight>
 
{{out}}
<pre>a{!=}{==}b{=}{!=}c</pre>
Line 1,248 ⟶ 1,564:
=={{header|Perl}}==
 
<langsyntaxhighlight Perllang="perl">sub multisplit {
my ($sep, $string, %opt) = @_ ;
$sep = join '|', map quotemeta($_), @$sep;
Line 1,258 ⟶ 1,574:
print "\n";
print "'$_' " for multisplit ['==','!=','='], "a!===b=!=c", keep_separators => 1;
print "\n";</langsyntaxhighlight>
 
{{Out}}
Line 1,265 ⟶ 1,581:
'a' '!=' '' '==' 'b' '=' '' '!=' 'c'
</pre>
 
=={{header|Perl 6}}==
{{Works with|rakudo|2015-11-29}}
<lang perl6>sub multisplit($str, @seps) { $str.split(/ ||@seps /, :v) }
 
my @chunks = multisplit( 'a!===b=!=c==d', < == != = > );
 
# Print the strings.
say @chunks».Str.perl;
 
# Print the positions of the separators.
for grep Match, @chunks -> $s {
say " $s from $s.from() to $s.to()";
}</lang>
{{out}}
<pre>("a", "!=", "", "==", "b", "=", "", "!=", "c", "==", "d")
!= from 1 to 3
== from 3 to 5
= from 6 to 7
!= from 7 to 9
== from 10 to 12</pre>
Using the array <tt>@seps</tt> in a pattern automatically does alternation.
By default this would do longest-term matching (that is, <tt>|</tt> semantics), but we can force it to do left-to-right matching by embedding the array in a short-circuit alternation (that is, <tt>||</tt> semantics).
As it happens, with the task's specified list of separators, it doesn't make any difference.
<p>
Perl 6 automatically returns Match objects that will stringify to the matched pattern, but can also be interrogated for their match positions, as illustrated above by post-processing the results two different ways.
 
=={{header|Phix}}==
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang Phix>procedure multisplit(string text, sequence delims)
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
integer k = 1, kdx
<span style="color: #008080;">procedure</span> <span style="color: #000000;">multisplit</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">text</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">delims</span><span style="color: #0000FF;">)</span>
while 1 do
<span style="color: #004080;">integer</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">kdx</span>
integer kmin = 0
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
for i=1 to length(delims) do
<span style="color: #004080;">integer</span> <span style="color: #000000;">kmin</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
integer ki = match(delims[i],text,k)
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">delims</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
if ki!=0 then
<span style="color: #004080;">integer</span> <span style="color: #000000;">ki</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">match</span><span style="color: #0000FF;">(</span><span style="color: #000000;">delims</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">text</span><span style="color: #0000FF;">,</span><span style="color: #000000;">k</span><span style="color: #0000FF;">)</span>
if kmin=0 or ki<kmin then
<span style="color: #008080;">if</span> <span style="color: #000000;">ki</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
kmin = ki
<span style="color: #008080;">if</span> <span style="color: #000000;">kmin</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">or</span> <span style="color: #000000;">ki</span><span style="color: #0000FF;"><</span><span style="color: #000000;">kmin</span> <span style="color: #008080;">then</span>
kdx = i
<span style="color: #000000;">kmin</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ki</span>
end if
<span style="color: #000000;">kdx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">i</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
string token = text[k..kmin-1]
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
if kmin=0 then
<span style="color: #004080;">string</span> <span style="color: #000000;">token</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">text</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">..</span><span style="color: #000000;">kmin</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span>
printf(1,"Token: [%s] at %d\n",{token,k})
<span style="color: #000000;">delim</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">kmin</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">?</span><span style="color: #008000;">""</span><span style="color: #0000FF;">:</span><span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">", delimiter (%s) at %d"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">delims</span><span style="color: #0000FF;">[</span><span style="color: #000000;">kdx</span><span style="color: #0000FF;">],</span><span style="color: #000000;">kmin</span><span style="color: #0000FF;">}))</span>
exit
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Token: [%s] at %d%s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">token</span><span style="color: #0000FF;">,</span><span style="color: #000000;">k</span><span style="color: #0000FF;">,</span><span style="color: #000000;">delim</span><span style="color: #0000FF;">})</span>
end if
<span style="color: #008080;">if</span> <span style="color: #000000;">kmin</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
printf(1,"Token: [%s] at %d, delimiter (%s) at %d\n",{token,k,delims[kdx],kmin})
<span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">kmin</span><span style="color: #0000FF;">+</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">delims</span><span style="color: #0000FF;">[</span><span style="color: #000000;">kdx</span><span style="color: #0000FF;">])</span>
k = kmin+length(delims[kdx])
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
end while
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
end procedure
 
<span style="color: #000000;">multisplit</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"a!===b=!=c"</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"=="</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"!="</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"="</span><span style="color: #0000FF;">})</span>
multisplit("a!===b=!=c",{"==","!=","="})</lang>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Line 1,327 ⟶ 1,618:
 
=={{header|PicoLisp}}==
<langsyntaxhighlight PicoLisplang="picolisp">(de multisplit (Str Sep)
(setq Sep (mapcar chop Sep))
(make
Line 1,345 ⟶ 1,636:
 
(println (multisplit "a!===b=!=c" '("==" "!=" "=")))
(println (multisplit "a!===b=!=c" '("=" "!=" "==")))</langsyntaxhighlight>
{{out}}
<pre>("a" (1 "!=") NIL (3 "==") "b" (6 "=") NIL (7 "!=") "c")
Line 1,351 ⟶ 1,642:
 
=={{header|Pike}}==
<langsyntaxhighlight Pikelang="pike">string input = "a!===b=!=c";
array sep = ({"==", "!=", "=" });
 
Line 1,367 ⟶ 1,658:
 
result;
Result: ({"a", ({"!=", 1}), "", ({"==", 3}), "b", ({"=", 6}), "", ({"!=", 7}), "c"})</langsyntaxhighlight>
 
=={{header|PowerShell}}==
<syntaxhighlight lang="powershell">
<lang PowerShell>
$string = "a!===b=!=c"
$separators = [regex]"(==|!=|=)"
Line 1,382 ⟶ 1,673:
 
$matchInfo
</syntaxhighlight>
</lang>
{{Out}}
<pre>
Line 1,394 ⟶ 1,685:
=={{header|Prolog}}==
Works with SWI-Prolog.
<langsyntaxhighlight Prologlang="prolog">multisplit(_LSep, '') -->
{!},
[].
Line 1,434 ⟶ 1,725:
my_sort(<, (N, N1, _), (N, N2, _)) :-
N1 > N2.
</syntaxhighlight>
</lang>
{{out}}
<pre>?- multisplit(['==', '!=', '='], 'ax!===b=!=c', Lst, []).
Line 1,441 ⟶ 1,732:
 
=={{header|Python}}==
===Procedural===
 
===Using Regularregular expressions===:
<langsyntaxhighlight lang="python">>>> import re
>>> def ms2(txt="a!===b=!=c", sep=["==", "!=", "="]):
if not txt or not sep:
Line 1,457 ⟶ 1,748:
['a', (1, 1), '', (0, 3), 'b', (2, 6), '', (1, 7), 'c']
>>> ms2(txt="a!===b=!=c", sep=["=", "!=", "=="])
['a', (1, 1), '', (0, 3), '', (0, 4), 'b', (0, 6), '', (1, 7), 'c']</langsyntaxhighlight>
 
===Not using RE's===regular expressions:
'''Inspired by C-version'''
<langsyntaxhighlight lang="python">def multisplit(text, sep):
lastmatch = i = 0
matches = []
Line 1,483 ⟶ 1,774:
>>> multisplit('a!===b=!=c', ['!=', '==', '='])
['a', (0, 1), (1, 3), 'b', (2, 6), (0, 7), 'c']
</syntaxhighlight>
</lang>
 
'''Alternative version'''
<langsyntaxhighlight lang="python">def min_pos(List):
return List.index(min(List))
 
Line 1,552 ⟶ 1,843:
S = "a!===b=!=c"
multisplit(S, ["==", "!=", "="]) # output: ['a', [1, 1], '', [0, 3], 'b', [2, 6], '', [1, 7], 'c']
multisplit(S, ["=", "!=", "=="]) # output: ['a', [1, 1], '', [0, 3], '', [0, 4], 'b', [0, 6], '', [1, 7], 'c']</langsyntaxhighlight>
 
===Functional===
In terms of a fold (reduce), without use of regular expressions:
{{Works with|Python|3.7}}
<syntaxhighlight lang="python">'''Multisplit'''
 
 
from functools import reduce
 
 
# multiSplit :: [String] -> String -> [(String, String, Int)]
def multiSplit(separators):
'''List of triples:
[(token, separator, start index of separator].
'''
def go(s):
def f(tokensPartsOffset, ic):
tokens, parts, offset = tokensPartsOffset
i, c = ic
inDelim = offset > i
return maybe(
(
tokens if inDelim
else c + tokens, parts, offset
)
)(
lambda x: (
'',
[(tokens, x, i)] + parts,
i + len(x)
)
)(
None if inDelim else find(
s[i:].startswith
)(separators)
)
ts, ps, _ = reduce(f, enumerate(s), ('', [], 0))
return list(reversed(ps)) + [(ts, '', len(s))]
return go
 
 
# ------------------------- TEST -------------------------
# main :: IO ()
def main():
'''String split on three successive separators.'''
print(
multiSplit(['==', '!=', '='])(
'a!===b=!=c'
)
)
 
 
# ------------------ GENERIC FUNCTIONS -------------------
 
# find :: (a -> Bool) -> [a] -> (a | None)
def find(p):
'''Just the first element in the list that matches p,
or None if no elements match.
'''
def go(xs):
try:
return next(x for x in xs if p(x))
except StopIteration:
return None
return go
 
 
# maybe :: b -> (a -> b) -> (a | None) -> b
def maybe(v):
'''Either the default value v, if m is None,
or the application of f to x.
'''
return lambda f: lambda m: v if (
None is m
) else f(m)
 
 
# MAIN ---
if __name__ == '__main__':
main()</syntaxhighlight>
{{Out}}
<pre>[('a', '!=', 1), ('', '==', 3), ('b', '=', 6), ('', '!=', 7), ('c', '', 10)]</pre>
 
=={{header|Racket}}==
 
<langsyntaxhighlight lang="racket">
#lang racket
(regexp-match* #rx"==|!=|=" "a!===b=!=c" #:gap-select? #t #:match-select values)
;; => '("a" ("!=") "" ("==") "b" ("=") "" ("!=") "c")
</syntaxhighlight>
</lang>
 
=={{header|Raku}}==
(formerly Perl 6)
<syntaxhighlight lang="raku" line>sub multisplit($str, @seps) { $str.split: / ||@seps /, :v }
 
my @chunks = multisplit 'a!===b=!=c==d', < == != = >;
 
# Print the strings.
say @chunks».Str.raku;
 
# Print the positions of the separators.
for grep Match, @chunks -> $s {
say "{$s.fmt: '%2s'} from {$s.from.fmt: '%2d'} to {$s.to.fmt: '%2d'}";
}</syntaxhighlight>
{{out}}
<pre>("a", "!=", "", "==", "b", "=", "", "!=", "c", "==", "d")
!= from 1 to 3
== from 3 to 5
= from 6 to 7
!= from 7 to 9
== from 10 to 12</pre>
Using the array <tt>@seps</tt> in a pattern automatically does alternation.
By default this would do longest-term matching (that is, <tt>|</tt> semantics), but we can force it to do left-to-right matching by embedding the array in a short-circuit alternation (that is, <tt>||</tt> semantics).
As it happens, with the task's specified list of separators, it doesn't make any difference.
<p>
Raku automatically returns Match objects that will stringify to the matched pattern, but can also be interrogated for their match positions, as illustrated above by post-processing the results two different ways.
 
=={{header|REXX}}==
<langsyntaxhighlight lang="rexx">/*REXX program splits a (character) string based on different separator delimiters.*/
parse arg $ /*obtain optional string from the C.L. */
if $='' then $= "a!===b=!=c" /*None specified? Then use the default*/
Line 1,588 ⟶ 1,987:
$=changestr(null, $, showNull) /* ··· showing of "null" chars. */
say 'new string:' $ /*now, display the new string to term. */
/*stick a fork in it, we're all done. */</langsyntaxhighlight>
Some older REXXes don't have a &nbsp; '''changestr''' &nbsp; BIF, so one is included here &nbsp; ──► &nbsp; [[CHANGESTR.REX]].
<br><br>'''output''' &nbsp; when using the default input:
Line 1,597 ⟶ 1,996:
 
=={{header|Ring}}==
<langsyntaxhighlight lang="ring">
# Project : Multisplit
 
Line 1,607 ⟶ 2,006:
see "" + n + ": " + substr(str, 1, pos-1) + " Sep By: " + sep[n] + nl
next
</syntaxhighlight>
</lang>
Output:
<pre>
Line 1,620 ⟶ 2,019:
The simple method, using a regular expression to split the text.
 
<langsyntaxhighlight lang="ruby">text = 'a!===b=!=c'
separators = ['==', '!=', '=']
 
Line 1,628 ⟶ 2,027:
 
p multisplit_simple(text, separators) # => ["a", "", "b", "", "c"]
</syntaxhighlight>
</lang>
 
The version that also returns the information about the separations.
 
<langsyntaxhighlight lang="ruby">def multisplit(text, separators)
sep_regex = Regexp.union(separators)
separator_info = []
Line 1,649 ⟶ 2,048:
 
p multisplit(text, separators)
# => [["a", "", "b", "", "c"], [["!=", 1], ["==", 3], ["=", 6], ["!=", 7]]]</langsyntaxhighlight>
 
Also demonstrating a method to rejoin the string given the separator information.
 
<langsyntaxhighlight lang="ruby">def multisplit_rejoin(info)
str = info[0].zip(info[1])[0..-2].inject("") {|str, (piece, (sep, idx))| str << piece << sep}
str << info[0].last
Line 1,659 ⟶ 2,058:
 
p multisplit_rejoin(multisplit(text, separators)) == text
# => true</langsyntaxhighlight>
 
=={{header|Run BASIC}}==
<langsyntaxhighlight lang="runbasic">str$ = "a!===b=!=c"
sep$ = "=== != =! b =!="
 
Line 1,670 ⟶ 2,069:
split$ = word$(str$,1,theSep$)
print i;" ";split$;" Sep By: ";theSep$
wend</langsyntaxhighlight>
{{out}}
<pre>1 a! Sep By: ===
Line 1,679 ⟶ 2,078:
 
=={{header|Scala}}==
<langsyntaxhighlight lang="scala">import scala.annotation.tailrec
def multiSplit(str:String, sep:Seq[String])={
def findSep(index:Int)=sep find (str startsWith (_, index))
Line 1,694 ⟶ 2,093:
}
 
println(multiSplit("a!===b=!=c", Seq("!=", "==", "=")))</langsyntaxhighlight>
{{out}}
<pre>List(a, , b, , c)</pre>
Line 1,700 ⟶ 2,099:
=={{header|Scheme}}==
{{works with|Gauche Scheme}}
<langsyntaxhighlight Schemelang="scheme">(use srfi-13)
(use srfi-42)
 
Line 1,714 ⟶ 2,113:
(define (glean shards)
(list-ec (: x (index i) shards)
(if (even? i)) x))</langsyntaxhighlight>
<b>Testing:</b>
<pre>
Line 1,727 ⟶ 2,126:
First approach, using line delimiters. Lines are delimited by an array of separator strings, normally [CRLF, LF, CR, lineSeparator(0x2028), paragraphSeparator(0x2029)]. Supplying an alternate set of delimiters lets us split a string by a different (ordered) set of strings:
 
<langsyntaxhighlight lang="sensetalk">set source to "a!===b=!=c"
set separators to ["==", "!=", "="]
 
put each line delimited by separators of source</langsyntaxhighlight>
Output:
<syntaxhighlight lang ="sensetalk">(a,,b,,c)</langsyntaxhighlight>
 
Second approach, using a pattern. SenseTalk's pattern language lets us define a pattern (a regex) which can then be used to split the string and also to display the actual separators that were found.
<langsyntaxhighlight lang="sensetalk">set source to "a!===b=!=c"
set separatorPattern to <"==" or "!=" or "=">
 
Line 1,741 ⟶ 2,140:
 
put each occurrence of separatorPattern in source
</syntaxhighlight>
</lang>
Output:
<langsyntaxhighlight lang="sensetalk">(a,,b,,c)
(!=,==,=,!=)</langsyntaxhighlight>
 
=={{header|Sidef}}==
<langsyntaxhighlight lang="ruby">func multisplit(sep, str, keep_sep=false) {
sep = sep.map{.escape}.join('|');
var re = Regex.new(keep_sep ? "(#{sep})" : sep);
Line 1,755 ⟶ 2,154:
[false, true].each { |bool|
say multisplit(%w(== != =), 'a!===b=!=c', keep_sep: bool);
}</langsyntaxhighlight>
{{out}}
<pre>
Line 1,761 ⟶ 2,160:
["a", "!=", "", "==", "b", "=", "", "!=", "c"]
</pre>
 
=={{header|Swift}}==
 
Swift strings are purposefully not index by integers to avoid confusion and performance traps when dealing with unicode. As such the indexes returned by this method are not very helpful to a human reader, but can be used to manipulate the original string.
 
{{trans|Python}}
 
<syntaxhighlight lang="swift">extension String {
func multiSplit(on seps: [String]) -> ([Substring], [(String, (start: String.Index, end: String.Index))]) {
var matches = [Substring]()
var matched = [(String, (String.Index, String.Index))]()
var i = startIndex
var lastMatch = startIndex
 
main: while i != endIndex {
for sep in seps where self[i...].hasPrefix(sep) {
if i > lastMatch {
matches.append(self[lastMatch..<i])
} else {
matches.append("")
}
 
lastMatch = index(i, offsetBy: sep.count)
matched.append((sep, (i, lastMatch)))
i = lastMatch
 
continue main
}
 
i = index(i, offsetBy: 1)
}
 
if i > lastMatch {
matches.append(self[lastMatch..<i])
}
 
return (matches, matched)
}
}
 
let (matches, matchedSeps) = "a!===b=!=c".multiSplit(on: ["==", "!=", "="])
 
print(matches, matchedSeps.map({ $0.0 }))</syntaxhighlight>
 
 
{{out}}
 
<pre>["a", "", "b", "", "c"] ["!=", "==", "=", "!="]</pre>
 
=={{header|Tcl}}==
This simple version does not retain information about what the separators were:
<langsyntaxhighlight lang="tcl">proc simplemultisplit {text sep} {
set map {}; foreach s $sep {lappend map $s "\uffff"}
return [split [string map $map $text] "\uffff"]
}
puts [simplemultisplit "a!===b=!=c" {"==" "!=" "="}]</langsyntaxhighlight>
{{out}}
<pre>a {} b {} c</pre>
Line 1,775 ⟶ 2,222:
to the match information (because the two collections of information
are of different lengths).
<langsyntaxhighlight lang="tcl">proc multisplit {text sep} {
foreach s $sep {lappend sr [regsub -all {\W} $s {\\&}]}
set sepRE [join $sr "|"]
Line 1,788 ⟶ 2,235:
}
return [list [lappend pieces [string range $text $start end]] $match]
}</langsyntaxhighlight>
Demonstration code:
<langsyntaxhighlight lang="tcl">set input "a!===b=!=c"
set matchers {"==" "!=" "="}
lassign [multisplit $input $matchers] substrings matchinfo
puts $substrings
puts $matchinfo</langsyntaxhighlight>
{{out}}
<pre>
Line 1,811 ⟶ 2,258:
The <code>:gap 0</code> makes the horizontal collect repetitions strictly adjacent. This means that <code>coll</code> will quit when faced with a nonmatching suffix portion of the data rather than scan forward (no gap allowed!). This creates an opportunity for the <code>tail</code> variable to grab the suffix which remains, which may be an empty string.
 
<langsyntaxhighlight lang="txr">@(next :args)
@(coll :gap 0)@(choose :shortest tok)@\
@tok@{sep /==/}@\
Line 1,821 ⟶ 2,268:
@(output)
@(rep)"@tok" {@sep} @(end)"@tail"
@(end)</langsyntaxhighlight>
 
Runs:
Line 1,846 ⟶ 2,293:
{{trans|Racket}}
 
<langsyntaxhighlight lang="sh">$ txr -p '(tok-str "a!===b=!=c" #/==|!=|=/ t)'
("a" "!=" "" "==" "b" "=" "" "!=" "c")</langsyntaxhighlight>
 
Here the third boolean argument means "keep the material between the tokens", which in the Racket version seems to be requested by the argument <code>#:gap-select? #:t</code>.
Line 1,853 ⟶ 2,300:
=={{header|UNIX Shell}}==
{{works with|bash}}
<langsyntaxhighlight lang="bash">multisplit() {
local str=$1
shift
Line 1,881 ⟶ 2,328:
if [[ $original == $recreated ]]; then
echo "successfully able to recreate original string"
fi</langsyntaxhighlight>
 
{{out}}
Line 1,892 ⟶ 2,339:
 
=={{header|VBScript}}==
<syntaxhighlight lang="vb">
<lang vb>
Function multisplit(s,sep)
arr_sep = Split(sep,"|")
Line 1,919 ⟶ 2,366:
WScript.StdOut.WriteLine
WScript.StdOut.Write "Extra Credit: " & multisplit_extra("a!===b=!=c","!=|==|=")
WScript.StdOut.WriteLine</langsyntaxhighlight>
{{out}}
<pre>
Line 1,925 ⟶ 2,372:
Extra Credit: a(!=)(==)b(=)(!=)c
</pre>
 
=={{header|V (Vlang)}}==
Without using additional libraries or regular expressions:
<syntaxhighlight lang="v (vlang)">fn main() {
str := "a!===b=!=c"
sep := ["==","!=","="]
println(ms(str, sep))
}
 
fn ms(txt string, sep []string) (map[int]string, []string, []string) {
mut ans, mut extra := []string{}, []string{}
mut place := map[int]string{}
mut temp :=''
mut vlen := 0
 
for slen in sep {if slen.len > vlen {vlen = slen.len}}
for cidx, cval in txt {
temp += cval.ascii_str()
for value in sep {
if temp.contains(value) && temp.len >= vlen {
place[cidx] = value
temp =''
}
}
}
 
for tidx, tval in txt {
for pkey, pval in place {
if tidx == pkey {
ans << ''
extra << '(' + pval + ')'
}
}
if sep.any(it.contains(tval.ascii_str())) == false {
ans << tval.ascii_str()
extra << tval.ascii_str()
}
}
println('Ending indices: $place')
println('Answer: $ans')
println('Extra: $extra')
return place, ans, extra
}</syntaxhighlight>
{{out}}
<pre>
Ending indices: {2: '!=', 4: '==', 6: '=', 8: '!='}
Answer: ['a', '', '', 'b', '', '', 'c']
Extra: ['a', '(!=)', '(==)', 'b', '(=)', '(!=)', 'c']
({2: '!=', 4: '==', 6: '=', 8: '!='}, ['a', '', '', 'b', '', '', 'c'], ['a', '(!=)', '(==)', 'b', '(=)', '(!=)', 'c'])
</pre>
 
=={{header|Wren}}==
{{libheader|Wren-pattern}}
{{libheader|Wren-fmt}}
<syntaxhighlight lang="wren">import "./pattern" for Pattern
import "./fmt" for Fmt
 
var input = "a!===b=!=c"
var p = Pattern.new("[/=/=|!/=|/=]")
var separators = p.findAll(input)
System.print("The separators matched and their starting/ending indices are:")
for (sep in separators) {
System.print(" %(Fmt.s(-4, Fmt.q(sep.text))) between %(sep.span)")
}
var parts = p.splitAll(input)
System.print("\nThe substrings between the separators are:")
System.print(parts.map { |p| (p != "") ? Fmt.q(p) : "empty string" }.toList)</syntaxhighlight>
 
{{out}}
<pre>
The separators matched and their starting/ending indices are:
"!=" between [1, 2]
"==" between [3, 4]
"=" between [6, 6]
"!=" between [7, 8]
 
The substrings between the separators are:
["a", empty string, "b", empty string, "c"]
</pre>
 
=={{header|XPL0}}==
<syntaxhighlight lang "XPL0">include xpllib; \for StrLen, StrNCmp, and Print
 
proc MultiSplit(Str, Seps, N);
char Str; int Seps, N;
int S, Ch, SepLen;
[while Str(0) # 0 do
[for S:= 0 to N-1 do
[SepLen:= StrLen(Seps(S));
if StrNCmp(Str, Seps(S), SepLen) = 0 then
[Print(" (%s) ", Seps(S));
Str:= Str + SepLen;
S:= 100;
];
];
if S < 100 then
[Ch:= Str(0); Str:= Str+1;
if Ch # 0 then ChOut(0, Ch);
];
];
];
 
MultiSplit("a!===b=!=c", ["==", "!=", "="], 3)</syntaxhighlight>
{{out}}
<pre>
a (!=) (==) b (=) (!=) c</pre>
 
=={{header|Yabasic}}==
<langsyntaxhighlight Yabasiclang="yabasic">t$ = "a!===b=!=c"
s$ = "==,!=,="
 
Line 1,945 ⟶ 2,499:
print left$(t$, l - 1), " with separator ", n$(j)
t$ = right$(t$, len(t$) - (l + len(n$(j))) + 1)
loop</langsyntaxhighlight>
 
=={{header|zkl}}==
{{trans|Python}}
<langsyntaxhighlight lang="zkl">fcn multisplit(text, sep){
lastmatch := i := 0; matches := List();
while(i < text.len()){
Line 1,965 ⟶ 2,519:
if(i > lastmatch) matches.append(text[lastmatch,i-lastmatch]);
return(matches);
}</langsyntaxhighlight>
<langsyntaxhighlight lang="zkl">multisplit("a!===b=!=c", T("==", "!=", "=")).println();
multisplit("a!===b=!=c", T("!=", "==", "=")).println();</langsyntaxhighlight>
{{out}}
<pre>
2,041

edits