diff options
author | Robert Hensing <roberth@users.noreply.github.com> | 2022-10-24 13:22:42 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-24 13:22:42 +0200 |
commit | bc4ce318bf6aa52031ad891675c573ce31308c8d (patch) | |
tree | fde3afb99befe8b7cfa46ae90cab9536bf19cdf6 /lib/strings.nix | |
parent | df9da891637929d52a8a189ea3399c1ee555ef51 (diff) | |
parent | ed71173841618bd4c69f40d07fb467ccabc5db0b (diff) |
Merge pull request #173949 from jacoblambda/fix-toInt-zero-padding
lib: add strings.toIntBase10 to parse zero-padded strings
Diffstat (limited to 'lib/strings.nix')
-rw-r--r-- | lib/strings.nix | 93 |
1 files changed, 87 insertions, 6 deletions
diff --git a/lib/strings.nix b/lib/strings.nix index af26532aa4305..b5f5a4d9060ba 100644 --- a/lib/strings.nix +++ b/lib/strings.nix @@ -783,24 +783,105 @@ rec { else false; - /* Parse a string as an int. + /* Parse a string as an int. Does not support parsing of integers with preceding zero due to + ambiguity between zero-padded and octal numbers. See toIntBase10. Type: string -> int Example: + toInt "1337" => 1337 + toInt "-4" => -4 + + toInt " 123 " + => 123 + + toInt "00024" + => error: Ambiguity in interpretation of 00024 between octal and zero padded integer. + toInt "3.14" => error: floating point JSON numbers are not supported */ - # Obviously, it is a bit hacky to use fromJSON this way. toInt = str: - let may_be_int = fromJSON str; in - if isInt may_be_int - then may_be_int - else throw "Could not convert ${str} to int."; + let + # RegEx: Match any leading whitespace, then any digits, and finally match any trailing + # whitespace. + strippedInput = match "[[:space:]]*([[:digit:]]+)[[:space:]]*" str; + + # RegEx: Match a leading '0' then one or more digits. + isLeadingZero = match "0[[:digit:]]+" (head strippedInput) == []; + + # Attempt to parse input + parsedInput = fromJSON (head strippedInput); + + generalError = "toInt: Could not convert ${escapeNixString str} to int."; + + octalAmbigError = "toInt: Ambiguity in interpretation of ${escapeNixString str}" + + " between octal and zero padded integer."; + + in + # Error on presence of non digit characters. + if strippedInput == null + then throw generalError + # Error on presence of leading zero/octal ambiguity. + else if isLeadingZero + then throw octalAmbigError + # Error if parse function fails. + else if !isInt parsedInput + then throw generalError + # Return result. + else parsedInput; + + + /* Parse a string as a base 10 int. This supports parsing of zero-padded integers. + + Type: string -> int + + Example: + toIntBase10 "1337" + => 1337 + + toIntBase10 "-4" + => -4 + + toIntBase10 " 123 " + => 123 + + toIntBase10 "00024" + => 24 + + toIntBase10 "3.14" + => error: floating point JSON numbers are not supported + */ + toIntBase10 = str: + let + # RegEx: Match any leading whitespace, then match any zero padding, capture any remaining + # digits after that, and finally match any trailing whitespace. + strippedInput = match "[[:space:]]*0*([[:digit:]]+)[[:space:]]*" str; + + # RegEx: Match at least one '0'. + isZero = match "0+" (head strippedInput) == []; + + # Attempt to parse input + parsedInput = fromJSON (head strippedInput); + + generalError = "toIntBase10: Could not convert ${escapeNixString str} to int."; + + in + # Error on presence of non digit characters. + if strippedInput == null + then throw generalError + # In the special case zero-padded zero (00000), return early. + else if isZero + then 0 + # Error if parse function fails. + else if !isInt parsedInput + then throw generalError + # Return result. + else parsedInput; /* Read a list of paths from `file`, relative to the `rootPath`. Lines beginning with `#` are treated as comments and ignored. |