Skip to content

Commit

Permalink
Merge pull request #315411 from MattSturgeon/trim
Browse files Browse the repository at this point in the history
lib.strings: add `trim` and `trimWith`
  • Loading branch information
infinisil authored Jul 25, 2024
2 parents c3b21e1 + aad87c2 commit 91a3ba9
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 1 deletion.
2 changes: 1 addition & 1 deletion lib/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
62 changes: 62 additions & 0 deletions lib/strings.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
66 changes: 66 additions & 0 deletions lib/tests/misc.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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" ];
Expand Down

0 comments on commit 91a3ba9

Please sign in to comment.