56 lines
2.0 KiB
Nim
56 lines
2.0 KiB
Nim
# From: https://github.com/nim-lang/Nim/pull/11067/
|
|
proc parseHex*[T: SomeInteger](s: string, number: var T, start = 0, maxLen = 0): int
|
|
{.inline, noSideEffect.} =
|
|
## Parses a hexadecimal number and stores its value in ``number``.
|
|
##
|
|
## Returns the number of the parsed characters or 0 in case of an error.
|
|
## If error, the value of ``number`` is not changed.
|
|
##
|
|
## If ``maxLen == 0``, the parsing continues until the first non-hex character
|
|
## or to the end of the string. Otherwise, no more than ``maxLen`` characters
|
|
## are parsed starting from the ``start`` position.
|
|
##
|
|
## It does not check for overflow. If the value represented by the string is
|
|
## too big to fit into ``number``, only the value of last fitting characters
|
|
## will be stored in ``number`` without producing an error.
|
|
runnableExamples:
|
|
var num: int
|
|
doAssert parseHex("4E_69_ED", num) == 8
|
|
doAssert num == 5138925
|
|
doAssert parseHex("X", num) == 0
|
|
doAssert parseHex("#ABC", num) == 4
|
|
var num8: int8
|
|
doAssert parseHex("0x_4E_69_ED", num8) == 11
|
|
doAssert num8 == 0xED'i8
|
|
doAssert parseHex("0x_4E_69_ED", num8, 3, 2) == 2
|
|
doAssert num8 == 0x4E'i8
|
|
var num8u: uint8
|
|
doAssert parseHex("0x_4E_69_ED", num8u) == 11
|
|
doAssert num8u == 237
|
|
var num64: int64
|
|
doAssert parseHex("4E69ED4E69ED", num64) == 12
|
|
doAssert num64 == 86216859871725
|
|
var i = start
|
|
var output = T(0)
|
|
var foundDigit = false
|
|
let last = min(s.len, if maxLen == 0: s.len else: i + maxLen)
|
|
if i + 1 < last and s[i] == '0' and (s[i+1] in {'x', 'X'}): inc(i, 2)
|
|
elif i < last and s[i] == '#': inc(i)
|
|
while i < last:
|
|
case s[i]
|
|
of '_': discard
|
|
of '0'..'9':
|
|
output = output shl 4 or T(ord(s[i]) - ord('0'))
|
|
foundDigit = true
|
|
of 'a'..'f':
|
|
output = output shl 4 or T(ord(s[i]) - ord('a') + 10)
|
|
foundDigit = true
|
|
of 'A'..'F':
|
|
output = output shl 4 or T(ord(s[i]) - ord('A') + 10)
|
|
foundDigit = true
|
|
else: break
|
|
inc(i)
|
|
if foundDigit:
|
|
number = output
|
|
result = i - start
|