Multisplit: Difference between revisions

Content added Content deleted
(→‎{{header|Haskell}}: Additional example (multisplit by fold))
(→‎{{header|JavaScript}}: ES6 (without importing Underscore, and generalising to allow for any set of delimiters))
Line 826:
 
=={{header|JavaScript}}==
===ES5===
Based on Ruby example.
{{libheader|Underscore.js}}
Line 836 ⟶ 837:
return string.split(sep_regex);
}</lang>
 
===ES6===
Without importing an external library, and generalizing to allow for any set of delimiters (avoiding the need for a hand-crafted regex):
 
{{Trans|Haskell}} (Multisplit by fold example)
<lang javascript>(() => {
 
/// Delimiter list -> String -> list of parts, delimiters, offsets
 
// multiSplit :: [String] -> String ->
// [{part::String, delim::String, offset::Int}]
const multiSplit = (ds, s) => {
const
dcs = map(chars, ds),
xs = chars(s),
dct = foldl(
(a, c, i, s) => {
const
inDelim = a.offset > i,
mb = inDelim ? (
nothing('')
) : find(d => isPrefixOf(d, drop(i, xs)), dcs);
return mb.nothing ? {
tokens: a.tokens.concat(inDelim ? (
[]
) : [c]),
parts: a.parts,
offset: a.offset
} : {
tokens: [],
parts: append(a.parts, [{
part: intercalate('', a.tokens),
delim: intercalate('', mb.just),
offset: i
}]),
offset: i + length(mb.just)
};
}, {
tokens: [],
parts: [],
offset: 0
}, xs
);
return append(dct.parts, [{
part: intercalate('', dct.tokens),
delim: "",
offset: length(s)
}]);
};
 
// GENERIC FUNCTIONS -----------------------------------------------------
 
// append (++) :: [a] -> [a] -> [a]
const append = (xs, ys) => xs.concat(ys);
 
// chars :: String -> [Char]
const chars = s => s.split('');
 
// drop :: Int -> [a] -> [a]
// drop :: Int -> String -> String
const drop = (n, xs) => xs.slice(n);
 
// find :: (a -> Bool) -> [a] -> Maybe a
const find = (p, xs) => {
for (var i = 0, lng = xs.length; i < lng; i++) {
var x = xs[i];
if (p(x)) return just(x);
}
return nothing('Not found');
};
 
// foldl :: (a -> b -> a) -> a -> [b] -> a
const foldl = (f, a, xs) => xs.reduce(f, a);
 
// intercalate :: String -> [String] -> String
const intercalate = (s, xs) => xs.join(s);
 
// isPrefixOf takes two lists or strings and returns
// true iff the first is a prefix of the second.
// isPrefixOf :: [a] -> [a] -> Bool
// isPrefixOf :: String -> String -> Bool
const isPrefixOf = (xs, ys) => {
const pfx = (xs, ys) => xs.length ? (
ys.length ? xs[0] === ys[0] && pfx(
xs.slice(1), ys.slice(1)
) : false
) : true;
return typeof xs !== 'string' ? pfx(xs, ys) : ys.startsWith(xs);
};
 
// just :: a -> Just a
const just = x => ({
nothing: false,
just: x
});
 
// length :: [a] -> Int
const length = xs => xs.length;
 
// map :: (a -> b) -> [a] -> [b]
const map = (f, xs) => xs.map(f);
 
// nothing :: () -> Nothing
const nothing = (optionalMsg) => ({
nothing: true,
msg: optionalMsg
});
 
// show :: Int -> a -> Indented String
// show :: a -> String
const show = (...x) =>
JSON.stringify.apply(
null, x.length > 1 ? [x[1], null, x[0]] : x
);
 
// TEST ------------------------------------------------------------------
const
strTest = 'a!===b=!=c',
delims = ['==', '!=', '='];
 
return show(2,
multiSplit(delims, strTest)
);
})();</lang>
{{Out}}
<pre>[
{
"part": "a",
"delim": "!=",
"offset": 1
},
{
"part": "",
"delim": "==",
"offset": 3
},
{
"part": "b",
"delim": "=",
"offset": 6
},
{
"part": "",
"delim": "!=",
"offset": 7
},
{
"part": "c",
"delim": "",
"offset": 10
}
]</pre>
 
=={{header|jq}}==
{{Works with|jq|1.4}}