lib.strings: add trim
and trimWith
`strings.trim` returns a copy of the string with all leading and trailing whitespace removed. `strings.trimWith` does the same thing, but calling code can decide whether to trim the start and/or end of the string.
This commit is contained in:
parent
d1e70dde57
commit
aad87c2aa8
@ -105,7 +105,7 @@ let
|
||||
hasInfix hasPrefix hasSuffix stringToCharacters stringAsChars escape
|
||||
escapeShellArg escapeShellArgs
|
||||
isStorePath isStringLike
|
||||
isValidPosixName toShellVar toShellVars
|
||||
isValidPosixName toShellVar toShellVars trim trimWith
|
||||
escapeRegex escapeURL escapeXML replaceChars lowerChars
|
||||
upperChars toLower toUpper addContextFrom splitString
|
||||
removePrefix removeSuffix versionOlder versionAtLeast
|
||||
|
@ -157,6 +157,68 @@ rec {
|
||||
*/
|
||||
replicate = n: s: concatStrings (lib.lists.replicate n s);
|
||||
|
||||
/*
|
||||
Remove leading and trailing whitespace from a string.
|
||||
|
||||
Whitespace is defined as any of the following characters:
|
||||
" ", "\t" "\r" "\n"
|
||||
|
||||
Type: trim :: string -> string
|
||||
|
||||
Example:
|
||||
trim " hello, world! "
|
||||
=> "hello, world!"
|
||||
*/
|
||||
trim = trimWith {
|
||||
start = true;
|
||||
end = true;
|
||||
};
|
||||
|
||||
/*
|
||||
Remove leading and/or trailing whitespace from a string.
|
||||
|
||||
Whitespace is defined as any of the following characters:
|
||||
" ", "\t" "\r" "\n"
|
||||
|
||||
Type: trimWith :: Attrs -> string -> string
|
||||
|
||||
Example:
|
||||
trimWith { start = true; } " hello, world! "}
|
||||
=> "hello, world! "
|
||||
trimWith { end = true; } " hello, world! "}
|
||||
=> " hello, world!"
|
||||
*/
|
||||
trimWith =
|
||||
{
|
||||
# Trim leading whitespace
|
||||
start ? false,
|
||||
# Trim trailing whitespace
|
||||
end ? false,
|
||||
}:
|
||||
s:
|
||||
let
|
||||
# Define our own whitespace character class instead of using
|
||||
# `[:space:]`, which is not well-defined.
|
||||
chars = " \t\r\n";
|
||||
|
||||
# To match up until trailing whitespace, we need to capture a
|
||||
# group that ends with a non-whitespace character.
|
||||
regex =
|
||||
if start && end then
|
||||
"[${chars}]*(.*[^${chars}])[${chars}]*"
|
||||
else if start then
|
||||
"[${chars}]*(.*)"
|
||||
else if end then
|
||||
"(.*[^${chars}])[${chars}]*"
|
||||
else
|
||||
"(.*)";
|
||||
|
||||
# If the string was empty or entirely whitespace,
|
||||
# then the regex may not match and `res` will be `null`.
|
||||
res = match regex s;
|
||||
in
|
||||
optionalString (res != null) (head res);
|
||||
|
||||
/* Construct a Unix-style, colon-separated search path consisting of
|
||||
the given `subDir` appended to each of the given paths.
|
||||
|
||||
|
@ -369,6 +369,72 @@ runTests {
|
||||
expected = "hellohellohellohellohello";
|
||||
};
|
||||
|
||||
# Test various strings are trimmed correctly
|
||||
testTrimString = {
|
||||
expr =
|
||||
let
|
||||
testValues = f: mapAttrs (_: f) {
|
||||
empty = "";
|
||||
cr = "\r";
|
||||
lf = "\n";
|
||||
tab = "\t";
|
||||
spaces = " ";
|
||||
leading = " Hello, world";
|
||||
trailing = "Hello, world ";
|
||||
mixed = " Hello, world ";
|
||||
mixed-tabs = " \t\tHello, world \t \t ";
|
||||
multiline = " Hello,\n world! ";
|
||||
multiline-crlf = " Hello,\r\n world! ";
|
||||
};
|
||||
in
|
||||
{
|
||||
leading = testValues (strings.trimWith { start = true; });
|
||||
trailing = testValues (strings.trimWith { end = true; });
|
||||
both = testValues strings.trim;
|
||||
};
|
||||
expected = {
|
||||
leading = {
|
||||
empty = "";
|
||||
cr = "";
|
||||
lf = "";
|
||||
tab = "";
|
||||
spaces = "";
|
||||
leading = "Hello, world";
|
||||
trailing = "Hello, world ";
|
||||
mixed = "Hello, world ";
|
||||
mixed-tabs = "Hello, world \t \t ";
|
||||
multiline = "Hello,\n world! ";
|
||||
multiline-crlf = "Hello,\r\n world! ";
|
||||
};
|
||||
trailing = {
|
||||
empty = "";
|
||||
cr = "";
|
||||
lf = "";
|
||||
tab = "";
|
||||
spaces = "";
|
||||
leading = " Hello, world";
|
||||
trailing = "Hello, world";
|
||||
mixed = " Hello, world";
|
||||
mixed-tabs = " \t\tHello, world";
|
||||
multiline = " Hello,\n world!";
|
||||
multiline-crlf = " Hello,\r\n world!";
|
||||
};
|
||||
both = {
|
||||
empty = "";
|
||||
cr = "";
|
||||
lf = "";
|
||||
tab = "";
|
||||
spaces = "";
|
||||
leading = "Hello, world";
|
||||
trailing = "Hello, world";
|
||||
mixed = "Hello, world";
|
||||
mixed-tabs = "Hello, world";
|
||||
multiline = "Hello,\n world!";
|
||||
multiline-crlf = "Hello,\r\n world!";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
testSplitStringsSimple = {
|
||||
expr = strings.splitString "." "a.b.c.d";
|
||||
expected = [ "a" "b" "c" "d" ];
|
||||
|
Loading…
Reference in New Issue
Block a user