parseutils.nim 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2012 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module contains helpers for parsing tokens, numbers, integers, floats,
  10. ## identifiers, etc.
  11. ##
  12. ## To unpack raw bytes look at the `streams <streams.html>`_ module.
  13. ##
  14. ## ```nim test
  15. ## let logs = @["2019-01-10: OK_", "2019-01-11: FAIL_", "2019-01: aaaa"]
  16. ## var outp: seq[string]
  17. ##
  18. ## for log in logs:
  19. ## var res: string
  20. ## if parseUntil(log, res, ':') == 10: # YYYY-MM-DD == 10
  21. ## outp.add(res & " - " & captureBetween(log, ' ', '_'))
  22. ## doAssert outp == @["2019-01-10 - OK", "2019-01-11 - FAIL"]
  23. ## ```
  24. ##
  25. ## ```nim test
  26. ## from std/strutils import Digits, parseInt
  27. ##
  28. ## let
  29. ## input1 = "2019 school start"
  30. ## input2 = "3 years back"
  31. ## startYear = input1[0 .. skipWhile(input1, Digits)-1] # 2019
  32. ## yearsBack = input2[0 .. skipWhile(input2, Digits)-1] # 3
  33. ## examYear = parseInt(startYear) + parseInt(yearsBack)
  34. ## doAssert "Examination is in " & $examYear == "Examination is in 2022"
  35. ## ```
  36. ##
  37. ## **See also:**
  38. ## * `strutils module<strutils.html>`_ for combined and identical parsing proc's
  39. ## * `json module<json.html>`_ for a JSON parser
  40. ## * `parsecfg module<parsecfg.html>`_ for a configuration file parser
  41. ## * `parsecsv module<parsecsv.html>`_ for a simple CSV (comma separated value) parser
  42. ## * `parseopt module<parseopt.html>`_ for a command line parser
  43. ## * `parsexml module<parsexml.html>`_ for a XML / HTML parser
  44. ## * `other parsers<lib.html#pure-libraries-parsers>`_ for other parsers
  45. {.push debugger: off.} # the user does not want to trace a part
  46. # of the standard library!
  47. include "system/inclrtl"
  48. template toOa(s: string): openArray[char] = openArray[char](s)
  49. const
  50. Whitespace = {' ', '\t', '\v', '\r', '\l', '\f'}
  51. IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
  52. IdentStartChars = {'a'..'z', 'A'..'Z', '_'}
  53. ## copied from strutils
  54. proc toLower(c: char): char {.inline.} =
  55. result = if c in {'A'..'Z'}: chr(ord(c)-ord('A')+ord('a')) else: c
  56. proc parseBin*[T: SomeInteger](s: openArray[char], number: var T, maxLen = 0): int {.noSideEffect.} =
  57. ## Parses a binary number and stores its value in ``number``.
  58. ##
  59. ## Returns the number of the parsed characters or 0 in case of an error.
  60. ## If error, the value of ``number`` is not changed.
  61. ##
  62. ## If ``maxLen == 0``, the parsing continues until the first non-bin character
  63. ## or to the end of the string. Otherwise, no more than ``maxLen`` characters
  64. ## are parsed starting from the ``start`` position.
  65. ##
  66. ## It does not check for overflow. If the value represented by the string is
  67. ## too big to fit into ``number``, only the value of last fitting characters
  68. ## will be stored in ``number`` without producing an error.
  69. runnableExamples:
  70. var num: int
  71. doAssert parseBin("0100_1110_0110_1001_1110_1101", num) == 29
  72. doAssert num == 5138925
  73. doAssert parseBin("3", num) == 0
  74. var num8: int8
  75. doAssert parseBin("0b_0100_1110_0110_1001_1110_1101", num8) == 32
  76. doAssert num8 == 0b1110_1101'i8
  77. doAssert parseBin("0b_0100_1110_0110_1001_1110_1101", num8, 3, 9) == 9
  78. doAssert num8 == 0b0100_1110'i8
  79. var num8u: uint8
  80. doAssert parseBin("0b_0100_1110_0110_1001_1110_1101", num8u) == 32
  81. doAssert num8u == 237
  82. var num64: int64
  83. doAssert parseBin("0100111001101001111011010100111001101001", num64) == 40
  84. doAssert num64 == 336784608873
  85. var i = 0
  86. var output = T(0)
  87. var foundDigit = false
  88. let last = min(s.len, if maxLen == 0: s.len else: i + maxLen)
  89. if i + 1 < last and s[i] == '0' and (s[i+1] in {'b', 'B'}): inc(i, 2)
  90. while i < last:
  91. case s[i]
  92. of '_': discard
  93. of '0'..'1':
  94. output = output shl 1 or T(ord(s[i]) - ord('0'))
  95. foundDigit = true
  96. else: break
  97. inc(i)
  98. if foundDigit:
  99. number = output
  100. result = i
  101. else:
  102. result = 0
  103. proc parseOct*[T: SomeInteger](s: openArray[char], number: var T, maxLen = 0): int {.noSideEffect.} =
  104. ## Parses an octal number and stores its value in ``number``.
  105. ##
  106. ## Returns the number of the parsed characters or 0 in case of an error.
  107. ## If error, the value of ``number`` is not changed.
  108. ##
  109. ## If ``maxLen == 0``, the parsing continues until the first non-oct character
  110. ## or to the end of the string. Otherwise, no more than ``maxLen`` characters
  111. ## are parsed starting from the ``start`` position.
  112. ##
  113. ## It does not check for overflow. If the value represented by the string is
  114. ## too big to fit into ``number``, only the value of last fitting characters
  115. ## will be stored in ``number`` without producing an error.
  116. runnableExamples:
  117. var num: int
  118. doAssert parseOct("0o23464755", num) == 10
  119. doAssert num == 5138925
  120. doAssert parseOct("8", num) == 0
  121. var num8: int8
  122. doAssert parseOct("0o_1464_755", num8) == 11
  123. doAssert num8 == -19
  124. doAssert parseOct("0o_1464_755", num8, 3, 3) == 3
  125. doAssert num8 == 102
  126. var num8u: uint8
  127. doAssert parseOct("1464755", num8u) == 7
  128. doAssert num8u == 237
  129. var num64: int64
  130. doAssert parseOct("2346475523464755", num64) == 16
  131. doAssert num64 == 86216859871725
  132. var i = 0
  133. var output = T(0)
  134. var foundDigit = false
  135. let last = min(s.len, if maxLen == 0: s.len else: i + maxLen)
  136. if i + 1 < last and s[i] == '0' and (s[i+1] in {'o', 'O'}): inc(i, 2)
  137. while i < last:
  138. case s[i]
  139. of '_': discard
  140. of '0'..'7':
  141. output = output shl 3 or T(ord(s[i]) - ord('0'))
  142. foundDigit = true
  143. else: break
  144. inc(i)
  145. if foundDigit:
  146. number = output
  147. result = i
  148. else:
  149. result = 0
  150. proc parseHex*[T: SomeInteger](s: openArray[char], number: var T, maxLen = 0): int {.noSideEffect.} =
  151. ## Parses a hexadecimal number and stores its value in ``number``.
  152. ##
  153. ## Returns the number of the parsed characters or 0 in case of an error.
  154. ## If error, the value of ``number`` is not changed.
  155. ##
  156. ## If ``maxLen == 0``, the parsing continues until the first non-hex character
  157. ## or to the end of the string. Otherwise, no more than ``maxLen`` characters
  158. ## are parsed starting from the ``start`` position.
  159. ##
  160. ## It does not check for overflow. If the value represented by the string is
  161. ## too big to fit into ``number``, only the value of last fitting characters
  162. ## will be stored in ``number`` without producing an error.
  163. runnableExamples:
  164. var num: int
  165. doAssert parseHex("4E_69_ED", num) == 8
  166. doAssert num == 5138925
  167. doAssert parseHex("X", num) == 0
  168. doAssert parseHex("#ABC", num) == 4
  169. var num8: int8
  170. doAssert parseHex("0x_4E_69_ED", num8) == 11
  171. doAssert num8 == 0xED'i8
  172. doAssert parseHex("0x_4E_69_ED", num8, 3, 2) == 2
  173. doAssert num8 == 0x4E'i8
  174. var num8u: uint8
  175. doAssert parseHex("0x_4E_69_ED", num8u) == 11
  176. doAssert num8u == 237
  177. var num64: int64
  178. doAssert parseHex("4E69ED4E69ED", num64) == 12
  179. doAssert num64 == 86216859871725
  180. result = 0
  181. var i = 0
  182. var output = T(0)
  183. var foundDigit = false
  184. let last = min(s.len, if maxLen == 0: s.len else: i + maxLen)
  185. if i + 1 < last and s[i] == '0' and (s[i+1] in {'x', 'X'}): inc(i, 2)
  186. elif i < last and s[i] == '#': inc(i)
  187. while i < last:
  188. case s[i]
  189. of '_': discard
  190. of '0'..'9':
  191. output = output shl 4 or T(ord(s[i]) - ord('0'))
  192. foundDigit = true
  193. of 'a'..'f':
  194. output = output shl 4 or T(ord(s[i]) - ord('a') + 10)
  195. foundDigit = true
  196. of 'A'..'F':
  197. output = output shl 4 or T(ord(s[i]) - ord('A') + 10)
  198. foundDigit = true
  199. else: break
  200. inc(i)
  201. if foundDigit:
  202. number = output
  203. result = i
  204. proc parseIdent*(s: openArray[char], ident: var string): int =
  205. ## Parses an identifier and stores it in ``ident``. Returns
  206. ## the number of the parsed characters or 0 in case of an error.
  207. ## If error, the value of `ident` is not changed.
  208. runnableExamples:
  209. var res: string
  210. doAssert parseIdent("Hello World", res, 0) == 5
  211. doAssert res == "Hello"
  212. doAssert parseIdent("Hello World", res, 1) == 4
  213. doAssert res == "ello"
  214. doAssert parseIdent("Hello World", res, 6) == 5
  215. doAssert res == "World"
  216. var i = 0
  217. if i < s.len and s[i] in IdentStartChars:
  218. inc(i)
  219. while i < s.len and s[i] in IdentChars: inc(i)
  220. ident = substr(s.toOpenArray(0, i-1))
  221. result = i
  222. else:
  223. result = 0
  224. proc parseIdent*(s: openArray[char]): string =
  225. ## Parses an identifier and returns it or an empty string in
  226. ## case of an error.
  227. runnableExamples:
  228. doAssert parseIdent("Hello World", 0) == "Hello"
  229. doAssert parseIdent("Hello World", 1) == "ello"
  230. doAssert parseIdent("Hello World", 5) == ""
  231. doAssert parseIdent("Hello World", 6) == "World"
  232. var i = 0
  233. if i < s.len and s[i] in IdentStartChars:
  234. inc(i)
  235. while i < s.len and s[i] in IdentChars: inc(i)
  236. result = substr(s.toOpenArray(0, i - 1))
  237. else:
  238. result = ""
  239. proc parseChar*(s: openArray[char], c: var char): int =
  240. ## Parses a single character, stores it in `c` and returns 1.
  241. ## In case of error (if start >= s.len) it returns 0
  242. ## and the value of `c` is unchanged.
  243. runnableExamples:
  244. var c: char
  245. doAssert "nim".parseChar(c, 3) == 0
  246. doAssert c == '\0'
  247. doAssert "nim".parseChar(c, 0) == 1
  248. doAssert c == 'n'
  249. if s.len > 0:
  250. c = s[0]
  251. result = 1
  252. else:
  253. result = 0
  254. proc skipWhitespace*(s: openArray[char]): int {.inline.} =
  255. ## Skips the whitespace starting at ``s[start]``. Returns the number of
  256. ## skipped characters.
  257. runnableExamples:
  258. doAssert skipWhitespace("Hello World", 0) == 0
  259. doAssert skipWhitespace(" Hello World", 0) == 1
  260. doAssert skipWhitespace("Hello World", 5) == 1
  261. doAssert skipWhitespace("Hello World", 5) == 2
  262. result = 0
  263. while result < s.len and s[result] in Whitespace: inc(result)
  264. proc skip*(s, token: openArray[char]): int {.inline.} =
  265. ## Skips the `token` starting at ``s[start]``. Returns the length of `token`
  266. ## or 0 if there was no `token` at ``s[start]``.
  267. runnableExamples:
  268. doAssert skip("2019-01-22", "2019", 0) == 4
  269. doAssert skip("2019-01-22", "19", 0) == 0
  270. doAssert skip("2019-01-22", "19", 2) == 2
  271. doAssert skip("CAPlow", "CAP", 0) == 3
  272. doAssert skip("CAPlow", "cap", 0) == 0
  273. result = 0
  274. while result < s.len and result < token.len and
  275. s[result] == token[result]:
  276. inc(result)
  277. if result != token.len: result = 0
  278. proc skipIgnoreCase*(s, token: openArray[char]): int =
  279. ## Same as `skip` but case is ignored for token matching.
  280. runnableExamples:
  281. doAssert skipIgnoreCase("CAPlow", "CAP", 0) == 3
  282. doAssert skipIgnoreCase("CAPlow", "cap", 0) == 3
  283. result = 0
  284. while result < s.len and result < token.len and
  285. toLower(s[result]) == toLower(token[result]): inc(result)
  286. if result != token.len: result = 0
  287. proc skipUntil*(s: openArray[char], until: set[char]): int {.inline.} =
  288. ## Skips all characters until one char from the set `until` is found
  289. ## or the end is reached.
  290. ## Returns number of characters skipped.
  291. runnableExamples:
  292. doAssert skipUntil("Hello World", {'W', 'e'}, 0) == 1
  293. doAssert skipUntil("Hello World", {'W'}, 0) == 6
  294. doAssert skipUntil("Hello World", {'W', 'd'}, 0) == 6
  295. result = 0
  296. while result < s.len and s[result] notin until: inc(result)
  297. proc skipUntil*(s: openArray[char], until: char): int {.inline.} =
  298. ## Skips all characters until the char `until` is found
  299. ## or the end is reached.
  300. ## Returns number of characters skipped.
  301. runnableExamples:
  302. doAssert skipUntil("Hello World", 'o', 0) == 4
  303. doAssert skipUntil("Hello World", 'o', 4) == 0
  304. doAssert skipUntil("Hello World", 'W', 0) == 6
  305. doAssert skipUntil("Hello World", 'w', 0) == 11
  306. result = 0
  307. while result < s.len and s[result] != until: inc(result)
  308. proc skipWhile*(s: openArray[char], toSkip: set[char]): int {.inline.} =
  309. ## Skips all characters while one char from the set `toSkip` is found.
  310. ## Returns number of characters skipped.
  311. runnableExamples:
  312. doAssert skipWhile("Hello World", {'H', 'e'}) == 2
  313. doAssert skipWhile("Hello World", {'e'}) == 0
  314. doAssert skipWhile("Hello World", {'W', 'o', 'r'}, 6) == 3
  315. result = 0
  316. while result < s.len and s[result] in toSkip: inc(result)
  317. proc fastSubstr(s: openArray[char]; token: var string; length: int) =
  318. token.setLen length
  319. for i in 0 ..< length: token[i] = s[i]
  320. proc parseUntil*(s: openArray[char], token: var string, until: set[char]): int {.inline.} =
  321. ## Parses a token and stores it in ``token``. Returns
  322. ## the number of the parsed characters or 0 in case of an error. A token
  323. ## consists of the characters notin `until`.
  324. runnableExamples:
  325. var myToken: string
  326. doAssert parseUntil("Hello World", myToken, {'W', 'o', 'r'}) == 4
  327. doAssert myToken == "Hell"
  328. doAssert parseUntil("Hello World", myToken, {'W', 'r'}) == 6
  329. doAssert myToken == "Hello "
  330. doAssert parseUntil("Hello World", myToken, {'W', 'r'}, 3) == 3
  331. doAssert myToken == "lo "
  332. var i = 0
  333. while i < s.len and s[i] notin until: inc(i)
  334. result = i
  335. fastSubstr(s, token, result)
  336. #token = substr(s, start, i-1)
  337. proc parseUntil*(s: openArray[char], token: var string, until: char): int {.inline.} =
  338. ## Parses a token and stores it in ``token``. Returns
  339. ## the number of the parsed characters or 0 in case of an error. A token
  340. ## consists of any character that is not the `until` character.
  341. runnableExamples:
  342. var myToken: string
  343. doAssert parseUntil("Hello World", myToken, 'W') == 6
  344. doAssert myToken == "Hello "
  345. doAssert parseUntil("Hello World", myToken, 'o') == 4
  346. doAssert myToken == "Hell"
  347. doAssert parseUntil("Hello World", myToken, 'o', 2) == 2
  348. doAssert myToken == "ll"
  349. var i = 0
  350. while i < s.len and s[i] != until: inc(i)
  351. result = i
  352. fastSubstr(s, token, result)
  353. #token = substr(s, start, i-1)
  354. proc parseUntil*(s: openArray[char], token: var string, until: string): int {.inline.} =
  355. ## Parses a token and stores it in ``token``. Returns
  356. ## the number of the parsed characters or 0 in case of an error. A token
  357. ## consists of any character that comes before the `until` token.
  358. runnableExamples:
  359. var myToken: string
  360. doAssert parseUntil("Hello World", myToken, "Wor") == 6
  361. doAssert myToken == "Hello "
  362. doAssert parseUntil("Hello World", myToken, "Wor", 2) == 4
  363. doAssert myToken == "llo "
  364. when (NimMajor, NimMinor) <= (1, 0):
  365. if until.len == 0:
  366. token.setLen(0)
  367. return 0
  368. var i = 0
  369. while i < s.len:
  370. if until.len > 0 and s[i] == until[0]:
  371. var u = 1
  372. while i+u < s.len and u < until.len and s[i+u] == until[u]:
  373. inc u
  374. if u >= until.len: break
  375. inc(i)
  376. result = i
  377. fastSubstr(s, token, result)
  378. #token = substr(s, start, i-1)
  379. proc parseWhile*(s: openArray[char], token: var string, validChars: set[char]): int {.inline.} =
  380. ## Parses a token and stores it in ``token``. Returns
  381. ## the number of the parsed characters or 0 in case of an error. A token
  382. ## consists of the characters in `validChars`.
  383. runnableExamples:
  384. var myToken: string
  385. doAssert parseWhile("Hello World", myToken, {'W', 'o', 'r'}, 0) == 0
  386. doAssert myToken.len() == 0
  387. doAssert parseWhile("Hello World", myToken, {'W', 'o', 'r'}, 6) == 3
  388. doAssert myToken == "Wor"
  389. var i = 0
  390. while i < s.len and s[i] in validChars: inc(i)
  391. result = i
  392. fastSubstr(s, token, result)
  393. #token = substr(s, start, i-1)
  394. proc captureBetween*(s: openArray[char], first: char, second = '\0'): string =
  395. ## Finds the first occurrence of ``first``, then returns everything from there
  396. ## up to ``second`` (if ``second`` is '\0', then ``first`` is used).
  397. runnableExamples:
  398. doAssert captureBetween("Hello World", 'e') == "llo World"
  399. doAssert captureBetween("Hello World", 'e', 'r') == "llo Wo"
  400. doAssert captureBetween("Hello World".toOpenArray(6, "Hello World".high), 'l') == "d"
  401. var i = skipUntil(s, first) + 1
  402. result = ""
  403. discard parseUntil(s.toOpenArray(i, s.high), result, if second == '\0': first else: second)
  404. proc integerOutOfRangeError() {.noinline, noreturn.} =
  405. raise newException(ValueError, "Parsed integer outside of valid range")
  406. # See #6752
  407. when defined(js):
  408. {.push overflowChecks: off.}
  409. proc rawParseInt(s: openArray[char], b: var BiggestInt): int =
  410. var
  411. sign: BiggestInt = -1
  412. i = 0
  413. if i < s.len:
  414. if s[i] == '+': inc(i)
  415. elif s[i] == '-':
  416. inc(i)
  417. sign = 1
  418. if i < s.len and s[i] in {'0'..'9'}:
  419. b = 0
  420. while i < s.len and s[i] in {'0'..'9'}:
  421. let c = ord(s[i]) - ord('0')
  422. if b >= (low(BiggestInt) + c) div 10:
  423. b = b * 10 - c
  424. else:
  425. integerOutOfRangeError()
  426. inc(i)
  427. while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored
  428. if sign == -1 and b == low(BiggestInt):
  429. integerOutOfRangeError()
  430. else:
  431. b = b * sign
  432. result = i
  433. else:
  434. result = 0
  435. when defined(js):
  436. {.pop.} # overflowChecks: off
  437. proc parseBiggestInt*(s: openArray[char], number: var BiggestInt): int {.
  438. rtl, extern: "npuParseBiggestInt", noSideEffect, raises: [ValueError].} =
  439. ## Parses an integer and stores the value into `number`.
  440. ## Result is the number of processed chars or 0 if there is no integer.
  441. ## `ValueError` is raised if the parsed integer is out of the valid range.
  442. runnableExamples:
  443. var res: BiggestInt
  444. doAssert parseBiggestInt("9223372036854775807", res) == 19
  445. doAssert res == 9223372036854775807
  446. doAssert parseBiggestInt("-2024_05_09", res) == 11
  447. doAssert res == -20240509
  448. var res = BiggestInt(0)
  449. # use 'res' for exception safety (don't write to 'number' in case of an
  450. # overflow exception):
  451. result = rawParseInt(s, res)
  452. if result != 0:
  453. number = res
  454. proc parseInt*(s: openArray[char], number: var int): int {.
  455. rtl, extern: "npuParseInt", noSideEffect, raises: [ValueError].} =
  456. ## Parses an integer and stores the value into `number`.
  457. ## Result is the number of processed chars or 0 if there is no integer.
  458. ## `ValueError` is raised if the parsed integer is out of the valid range.
  459. runnableExamples:
  460. var res: int
  461. doAssert parseInt("-2024_05_02", res) == 11
  462. doAssert res == -20240502
  463. var res = BiggestInt(0)
  464. result = parseBiggestInt(s, res)
  465. when sizeof(int) <= 4:
  466. if res < low(int) or res > high(int):
  467. integerOutOfRangeError()
  468. if result != 0:
  469. number = int(res)
  470. proc parseSaturatedNatural*(s: openArray[char], b: var int): int {.
  471. raises: [].} =
  472. ## Parses a natural number into ``b``. This cannot raise an overflow
  473. ## error. ``high(int)`` is returned for an overflow.
  474. ## The number of processed character is returned.
  475. ## This is usually what you really want to use instead of `parseInt`:idx:.
  476. runnableExamples:
  477. var res = 0
  478. discard parseSaturatedNatural("848", res)
  479. doAssert res == 848
  480. var i = 0
  481. if i < s.len and s[i] == '+': inc(i)
  482. if i < s.len and s[i] in {'0'..'9'}:
  483. b = 0
  484. while i < s.len and s[i] in {'0'..'9'}:
  485. let c = ord(s[i]) - ord('0')
  486. if b <= (high(int) - c) div 10:
  487. b = b * 10 + c
  488. else:
  489. b = high(int)
  490. inc(i)
  491. while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored
  492. result = i
  493. else:
  494. result = 0
  495. proc rawParseUInt(s: openArray[char], b: var BiggestUInt): int =
  496. var
  497. res = 0.BiggestUInt
  498. prev = 0.BiggestUInt
  499. i = 0
  500. if i < s.len - 1 and s[i] == '-' and s[i + 1] in {'0'..'9'}:
  501. integerOutOfRangeError()
  502. if i < s.len and s[i] == '+': inc(i) # Allow
  503. if i < s.len and s[i] in {'0'..'9'}:
  504. b = 0
  505. while i < s.len and s[i] in {'0'..'9'}:
  506. prev = res
  507. res = res * 10 + (ord(s[i]) - ord('0')).BiggestUInt
  508. if prev > res:
  509. integerOutOfRangeError()
  510. inc(i)
  511. while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored
  512. b = res
  513. result = i
  514. else:
  515. result = 0
  516. proc parseBiggestUInt*(s: openArray[char], number: var BiggestUInt): int {.
  517. rtl, extern: "npuParseBiggestUInt", noSideEffect, raises: [ValueError].} =
  518. ## Parses an unsigned integer and stores the value
  519. ## into `number`.
  520. ## `ValueError` is raised if the parsed integer is out of the valid range.
  521. runnableExamples:
  522. var res: BiggestUInt
  523. doAssert parseBiggestUInt("12", res, 0) == 2
  524. doAssert res == 12
  525. doAssert parseBiggestUInt("1111111111111111111", res, 0) == 19
  526. doAssert res == 1111111111111111111'u64
  527. var res = BiggestUInt(0)
  528. # use 'res' for exception safety (don't write to 'number' in case of an
  529. # overflow exception):
  530. result = rawParseUInt(s, res)
  531. if result != 0:
  532. number = res
  533. proc parseUInt*(s: openArray[char], number: var uint): int {.
  534. rtl, extern: "npuParseUInt", noSideEffect, raises: [ValueError].} =
  535. ## Parses an unsigned integer and stores the value
  536. ## into `number`.
  537. ## `ValueError` is raised if the parsed integer is out of the valid range.
  538. runnableExamples:
  539. var res: uint
  540. doAssert parseUInt("3450", res) == 4
  541. doAssert res == 3450
  542. doAssert parseUInt("3450", res, 2) == 2
  543. doAssert res == 50
  544. var res = BiggestUInt(0)
  545. result = parseBiggestUInt(s, res)
  546. when sizeof(BiggestUInt) > sizeof(uint) and sizeof(uint) <= 4:
  547. if res > 0xFFFF_FFFF'u64:
  548. integerOutOfRangeError()
  549. if result != 0:
  550. number = uint(res)
  551. proc parseBiggestFloat*(s: openArray[char], number: var BiggestFloat): int {.
  552. magic: "ParseBiggestFloat", importc: "nimParseBiggestFloat", noSideEffect.}
  553. ## Parses a float and stores the value into `number`.
  554. ## Result is the number of processed chars or 0 if a parsing error
  555. ## occurred.
  556. proc parseFloat*(s: openArray[char], number: var float): int {.
  557. rtl, extern: "npuParseFloat", noSideEffect.} =
  558. ## Parses a float and stores the value into `number`.
  559. ## Result is the number of processed chars or 0 if there occurred a parsing
  560. ## error.
  561. runnableExamples:
  562. var res: float
  563. doAssert parseFloat("32", res, 0) == 2
  564. doAssert res == 32.0
  565. doAssert parseFloat("32.57", res, 0) == 5
  566. doAssert res == 32.57
  567. doAssert parseFloat("32.57", res, 3) == 2
  568. doAssert res == 57.00
  569. var bf = BiggestFloat(0.0)
  570. result = parseBiggestFloat(s, bf)
  571. if result != 0:
  572. number = bf
  573. func toLowerAscii(c: char): char =
  574. if c in {'A'..'Z'}: char(uint8(c) xor 0b0010_0000'u8) else: c
  575. func parseSize*(s: openArray[char], size: var int64, alwaysBin=false): int =
  576. ## Parse a size qualified by binary or metric units into `size`. This format
  577. ## is often called "human readable". Result is the number of processed chars
  578. ## or 0 on parse errors and size is rounded to the nearest integer. Trailing
  579. ## garbage like "/s" in "1k/s" is allowed and detected by `result < s.len`.
  580. ##
  581. ## To simplify use, following non-rare wild conventions, and since fractional
  582. ## data like milli-bytes is so rare, unit matching is case-insensitive but for
  583. ## the 'i' distinguishing binary-metric from metric (which cannot be 'I').
  584. ##
  585. ## An optional trailing 'B|b' is ignored but processed. I.e., you must still
  586. ## know if units are bytes | bits or infer this fact via the case of s[^1] (if
  587. ## users can even be relied upon to use 'B' for byte and 'b' for bit or have
  588. ## that be s[^1]).
  589. ##
  590. ## If `alwaysBin==true` then scales are always binary-metric, but e.g. "KiB"
  591. ## is still accepted for clarity. If the value would exceed the range of
  592. ## `int64`, `size` saturates to `int64.high`. Supported metric prefix chars
  593. ## include k, m, g, t, p, e, z, y (but z & y saturate unless the number is a
  594. ## small fraction).
  595. ##
  596. ## **See also:**
  597. ## * https://en.wikipedia.org/wiki/Binary_prefix
  598. ## * `formatSize module<strutils.html>`_ for formatting
  599. runnableExamples:
  600. var res: int64 # caller must still know if 'b' refers to bytes|bits
  601. doAssert parseSize("10.5 MB", res) == 7
  602. doAssert res == 10_500_000 # decimal metric Mega prefix
  603. doAssert parseSize("64 mib", res) == 6
  604. doAssert res == 67108864 # 64 shl 20
  605. doAssert parseSize("1G/h", res, true) == 2 # '/' stops parse
  606. doAssert res == 1073741824 # 1 shl 30, forced binary metric
  607. const prefix = "b" & "kmgtpezy" # byte|bit & lowCase metric-ish prefixes
  608. const scaleM = [1.0, 1e3, 1e6, 1e9, 1e12, 1e15, 1e18, 1e21, 1e24] # 10^(3*idx)
  609. const scaleB = [1.0, 1024, 1048576, 1073741824, 1099511627776.0, # 2^(10*idx)
  610. 1125899906842624.0, 1152921504606846976.0, # ldexp?
  611. 1.180591620717411303424e21, 1.208925819614629174706176e24]
  612. var number: float = 0.0
  613. var scale = 1.0
  614. result = parseFloat(s, number)
  615. if number < 0: # While parseFloat accepts negatives ..
  616. result = 0 #.. we do not since sizes cannot be < 0
  617. if result > 0:
  618. let start = result # Save spot to maybe unwind white to EOS
  619. while result < s.len and s[result] in Whitespace:
  620. inc result
  621. if result < s.len: # Illegal starting char => unity
  622. if (let si = prefix.find(s[result].toLowerAscii); si >= 0):
  623. inc result # Now parse the scale
  624. scale = if alwaysBin: scaleB[si] else: scaleM[si]
  625. if result < s.len and s[result] == 'i':
  626. scale = scaleB[si] # Switch from default to binary-metric
  627. inc result
  628. if result < s.len and s[result].toLowerAscii == 'b':
  629. inc result # Skip optional '[bB]'
  630. else: # Unwind result advancement when there..
  631. result = start #..is no unit to the end of `s`.
  632. var sizeF = number * scale + 0.5 # Saturate to int64.high when too big
  633. size = if sizeF > 9223372036854774784.0: int64.high else: sizeF.int64
  634. # Above constant=2^63-1024 avoids C UB; github.com/nim-lang/Nim/issues/20102 or
  635. # stackoverflow.com/questions/20923556/math-pow2-63-1-math-pow2-63-512-is-true
  636. type
  637. InterpolatedKind* = enum ## Describes for `interpolatedFragments`
  638. ## which part of the interpolated string is
  639. ## yielded; for example in "str$$$var${expr}"
  640. ikStr, ## ``str`` part of the interpolated string
  641. ikDollar, ## escaped ``$`` part of the interpolated string
  642. ikVar, ## ``var`` part of the interpolated string
  643. ikExpr ## ``expr`` part of the interpolated string
  644. iterator interpolatedFragments*(s: openArray[char]): tuple[kind: InterpolatedKind,
  645. value: string] =
  646. ## Tokenizes the string `s` into substrings for interpolation purposes.
  647. ##
  648. runnableExamples:
  649. var outp: seq[tuple[kind: InterpolatedKind, value: string]]
  650. for k, v in interpolatedFragments(" $this is ${an example} $$"):
  651. outp.add (k, v)
  652. doAssert outp == @[(ikStr, " "),
  653. (ikVar, "this"),
  654. (ikStr, " is "),
  655. (ikExpr, "an example"),
  656. (ikStr, " "),
  657. (ikDollar, "$")]
  658. var i = 0
  659. var kind: InterpolatedKind
  660. while true:
  661. var j = i
  662. if j < s.len and s[j] == '$':
  663. if j+1 < s.len and s[j+1] == '{':
  664. inc j, 2
  665. var nesting = 0
  666. block curlies:
  667. while j < s.len:
  668. case s[j]
  669. of '{': inc nesting
  670. of '}':
  671. if nesting == 0:
  672. inc j
  673. break curlies
  674. dec nesting
  675. else: discard
  676. inc j
  677. raise newException(ValueError,
  678. "Expected closing '}': " & substr(s.toOpenArray(i, s.high)))
  679. inc i, 2 # skip ${
  680. kind = ikExpr
  681. elif j+1 < s.len and s[j+1] in IdentStartChars:
  682. inc j, 2
  683. while j < s.len and s[j] in IdentChars: inc(j)
  684. inc i # skip $
  685. kind = ikVar
  686. elif j+1 < s.len and s[j+1] == '$':
  687. inc j, 2
  688. inc i # skip $
  689. kind = ikDollar
  690. else:
  691. raise newException(ValueError,
  692. "Unable to parse a variable name at " & substr(s.toOpenArray(i, s.high)))
  693. else:
  694. while j < s.len and s[j] != '$': inc j
  695. kind = ikStr
  696. if j > i:
  697. # do not copy the trailing } for ikExpr:
  698. yield (kind, substr(s.toOpenArray(i, j-1-ord(kind == ikExpr))))
  699. else:
  700. break
  701. i = j
  702. {.pop.}
  703. proc parseBin*[T: SomeInteger](s: string, number: var T, start = 0,
  704. maxLen = 0): int {.noSideEffect.} =
  705. ## Parses a binary number and stores its value in ``number``.
  706. ##
  707. ## Returns the number of the parsed characters or 0 in case of an error.
  708. ## If error, the value of ``number`` is not changed.
  709. ##
  710. ## If ``maxLen == 0``, the parsing continues until the first non-bin character
  711. ## or to the end of the string. Otherwise, no more than ``maxLen`` characters
  712. ## are parsed starting from the ``start`` position.
  713. ##
  714. ## It does not check for overflow. If the value represented by the string is
  715. ## too big to fit into ``number``, only the value of last fitting characters
  716. ## will be stored in ``number`` without producing an error.
  717. runnableExamples:
  718. var num: int
  719. doAssert parseBin("0100_1110_0110_1001_1110_1101", num) == 29
  720. doAssert num == 5138925
  721. doAssert parseBin("3", num) == 0
  722. var num8: int8
  723. doAssert parseBin("0b_0100_1110_0110_1001_1110_1101", num8) == 32
  724. doAssert num8 == 0b1110_1101'i8
  725. doAssert parseBin("0b_0100_1110_0110_1001_1110_1101", num8, 3, 9) == 9
  726. doAssert num8 == 0b0100_1110'i8
  727. var num8u: uint8
  728. doAssert parseBin("0b_0100_1110_0110_1001_1110_1101", num8u) == 32
  729. doAssert num8u == 237
  730. var num64: int64
  731. doAssert parseBin("0100111001101001111011010100111001101001", num64) == 40
  732. doAssert num64 == 336784608873
  733. parseBin(s.toOpenArray(start, s.high), number, maxLen)
  734. proc parseOct*[T: SomeInteger](s: string, number: var T, start = 0,
  735. maxLen = 0): int {.noSideEffect.} =
  736. ## Parses an octal number and stores its value in ``number``.
  737. ##
  738. ## Returns the number of the parsed characters or 0 in case of an error.
  739. ## If error, the value of ``number`` is not changed.
  740. ##
  741. ## If ``maxLen == 0``, the parsing continues until the first non-oct character
  742. ## or to the end of the string. Otherwise, no more than ``maxLen`` characters
  743. ## are parsed starting from the ``start`` position.
  744. ##
  745. ## It does not check for overflow. If the value represented by the string is
  746. ## too big to fit into ``number``, only the value of last fitting characters
  747. ## will be stored in ``number`` without producing an error.
  748. runnableExamples:
  749. var num: int
  750. doAssert parseOct("0o23464755", num) == 10
  751. doAssert num == 5138925
  752. doAssert parseOct("8", num) == 0
  753. var num8: int8
  754. doAssert parseOct("0o_1464_755", num8) == 11
  755. doAssert num8 == -19
  756. doAssert parseOct("0o_1464_755", num8, 3, 3) == 3
  757. doAssert num8 == 102
  758. var num8u: uint8
  759. doAssert parseOct("1464755", num8u) == 7
  760. doAssert num8u == 237
  761. var num64: int64
  762. doAssert parseOct("2346475523464755", num64) == 16
  763. doAssert num64 == 86216859871725
  764. parseOct(s.toOpenArray(start, s.high), number, maxLen)
  765. proc parseHex*[T: SomeInteger](s: string, number: var T, start = 0,
  766. maxLen = 0): int {.noSideEffect.} =
  767. ## Parses a hexadecimal number and stores its value in ``number``.
  768. ##
  769. ## Returns the number of the parsed characters or 0 in case of an error.
  770. ## If error, the value of ``number`` is not changed.
  771. ##
  772. ## If ``maxLen == 0``, the parsing continues until the first non-hex character
  773. ## or to the end of the string. Otherwise, no more than ``maxLen`` characters
  774. ## are parsed starting from the ``start`` position.
  775. ##
  776. ## It does not check for overflow. If the value represented by the string is
  777. ## too big to fit into ``number``, only the value of last fitting characters
  778. ## will be stored in ``number`` without producing an error.
  779. runnableExamples:
  780. var num: int
  781. doAssert parseHex("4E_69_ED", num) == 8
  782. doAssert num == 5138925
  783. doAssert parseHex("X", num) == 0
  784. doAssert parseHex("#ABC", num) == 4
  785. var num8: int8
  786. doAssert parseHex("0x_4E_69_ED", num8) == 11
  787. doAssert num8 == 0xED'i8
  788. doAssert parseHex("0x_4E_69_ED", num8, 3, 2) == 2
  789. doAssert num8 == 0x4E'i8
  790. var num8u: uint8
  791. doAssert parseHex("0x_4E_69_ED", num8u) == 11
  792. doAssert num8u == 237
  793. var num64: int64
  794. doAssert parseHex("4E69ED4E69ED", num64) == 12
  795. doAssert num64 == 86216859871725
  796. parseHex(s.toOpenArray(start, s.high), number, maxLen)
  797. proc parseIdent*(s: string, ident: var string, start = 0): int =
  798. ## Parses an identifier and stores it in ``ident``. Returns
  799. ## the number of the parsed characters or 0 in case of an error.
  800. ## If error, the value of `ident` is not changed.
  801. runnableExamples:
  802. var res: string
  803. doAssert parseIdent("Hello World", res, 0) == 5
  804. doAssert res == "Hello"
  805. doAssert parseIdent("Hello World", res, 1) == 4
  806. doAssert res == "ello"
  807. doAssert parseIdent("Hello World", res, 6) == 5
  808. doAssert res == "World"
  809. parseIdent(s.toOpenArray(start, s.high), ident)
  810. proc parseIdent*(s: string, start = 0): string =
  811. ## Parses an identifier and returns it or an empty string in
  812. ## case of an error.
  813. runnableExamples:
  814. doAssert parseIdent("Hello World", 0) == "Hello"
  815. doAssert parseIdent("Hello World", 1) == "ello"
  816. doAssert parseIdent("Hello World", 5) == ""
  817. doAssert parseIdent("Hello World", 6) == "World"
  818. parseIdent(s.toOpenArray(start, s.high))
  819. proc parseChar*(s: string, c: var char, start = 0): int =
  820. ## Parses a single character, stores it in `c` and returns 1.
  821. ## In case of error (if start >= s.len) it returns 0
  822. ## and the value of `c` is unchanged.
  823. runnableExamples:
  824. var c: char
  825. doAssert "nim".parseChar(c, 3) == 0
  826. doAssert c == '\0'
  827. doAssert "nim".parseChar(c, 0) == 1
  828. doAssert c == 'n'
  829. parseChar(s.toOpenArray(start, s.high), c)
  830. proc skipWhitespace*(s: string, start = 0): int {.inline.} =
  831. ## Skips the whitespace starting at ``s[start]``. Returns the number of
  832. ## skipped characters.
  833. runnableExamples:
  834. doAssert skipWhitespace("Hello World", 0) == 0
  835. doAssert skipWhitespace(" Hello World", 0) == 1
  836. doAssert skipWhitespace("Hello World", 5) == 1
  837. doAssert skipWhitespace("Hello World", 5) == 2
  838. skipWhitespace(s.toOpenArray(start, s.high))
  839. proc skip*(s, token: string, start = 0): int {.inline.} =
  840. ## Skips the `token` starting at ``s[start]``. Returns the length of `token`
  841. ## or 0 if there was no `token` at ``s[start]``.
  842. runnableExamples:
  843. doAssert skip("2019-01-22", "2019", 0) == 4
  844. doAssert skip("2019-01-22", "19", 0) == 0
  845. doAssert skip("2019-01-22", "19", 2) == 2
  846. doAssert skip("CAPlow", "CAP", 0) == 3
  847. doAssert skip("CAPlow", "cap", 0) == 0
  848. skip(s.toOpenArray(start, s.high), token)
  849. proc skipIgnoreCase*(s, token: string, start = 0): int =
  850. ## Same as `skip` but case is ignored for token matching.
  851. runnableExamples:
  852. doAssert skipIgnoreCase("CAPlow", "CAP", 0) == 3
  853. doAssert skipIgnoreCase("CAPlow", "cap", 0) == 3
  854. skipIgnoreCase(s.toOpenArray(start, s.high), token)
  855. proc skipUntil*(s: string, until: set[char], start = 0): int {.inline.} =
  856. ## Skips all characters until one char from the set `until` is found
  857. ## or the end is reached.
  858. ## Returns number of characters skipped.
  859. runnableExamples:
  860. doAssert skipUntil("Hello World", {'W', 'e'}, 0) == 1
  861. doAssert skipUntil("Hello World", {'W'}, 0) == 6
  862. doAssert skipUntil("Hello World", {'W', 'd'}, 0) == 6
  863. skipUntil(s.toOpenArray(start, s.high), until)
  864. proc skipUntil*(s: string, until: char, start = 0): int {.inline.} =
  865. ## Skips all characters until the char `until` is found
  866. ## or the end is reached.
  867. ## Returns number of characters skipped.
  868. runnableExamples:
  869. doAssert skipUntil("Hello World", 'o', 0) == 4
  870. doAssert skipUntil("Hello World", 'o', 4) == 0
  871. doAssert skipUntil("Hello World", 'W', 0) == 6
  872. doAssert skipUntil("Hello World", 'w', 0) == 11
  873. skipUntil(s.toOpenArray(start, s.high), until)
  874. proc skipWhile*(s: string, toSkip: set[char], start = 0): int {.inline.} =
  875. ## Skips all characters while one char from the set `toSkip` is found.
  876. ## Returns number of characters skipped.
  877. runnableExamples:
  878. doAssert skipWhile("Hello World", {'H', 'e'}) == 2
  879. doAssert skipWhile("Hello World", {'e'}) == 0
  880. doAssert skipWhile("Hello World", {'W', 'o', 'r'}, 6) == 3
  881. skipWhile(s.toOpenArray(start, s.high), toSkip)
  882. proc parseUntil*(s: string, token: var string, until: set[char],
  883. start = 0): int {.inline.} =
  884. ## Parses a token and stores it in ``token``. Returns
  885. ## the number of the parsed characters or 0 in case of an error. A token
  886. ## consists of the characters notin `until`.
  887. runnableExamples:
  888. var myToken: string
  889. doAssert parseUntil("Hello World", myToken, {'W', 'o', 'r'}) == 4
  890. doAssert myToken == "Hell"
  891. doAssert parseUntil("Hello World", myToken, {'W', 'r'}) == 6
  892. doAssert myToken == "Hello "
  893. doAssert parseUntil("Hello World", myToken, {'W', 'r'}, 3) == 3
  894. doAssert myToken == "lo "
  895. parseUntil(s.toOpenArray(start, s.high), token, until)
  896. proc parseUntil*(s: string, token: var string, until: char,
  897. start = 0): int {.inline.} =
  898. ## Parses a token and stores it in ``token``. Returns
  899. ## the number of the parsed characters or 0 in case of an error. A token
  900. ## consists of any character that is not the `until` character.
  901. runnableExamples:
  902. var myToken: string
  903. doAssert parseUntil("Hello World", myToken, 'W') == 6
  904. doAssert myToken == "Hello "
  905. doAssert parseUntil("Hello World", myToken, 'o') == 4
  906. doAssert myToken == "Hell"
  907. doAssert parseUntil("Hello World", myToken, 'o', 2) == 2
  908. doAssert myToken == "ll"
  909. parseUntil(s.toOpenArray(start, s.high), token, until)
  910. proc parseUntil*(s: string, token: var string, until: string,
  911. start = 0): int {.inline.} =
  912. ## Parses a token and stores it in ``token``. Returns
  913. ## the number of the parsed characters or 0 in case of an error. A token
  914. ## consists of any character that comes before the `until` token.
  915. runnableExamples:
  916. var myToken: string
  917. doAssert parseUntil("Hello World", myToken, "Wor") == 6
  918. doAssert myToken == "Hello "
  919. doAssert parseUntil("Hello World", myToken, "Wor", 2) == 4
  920. doAssert myToken == "llo "
  921. parseUntil(s.toOpenArray(start, s.high), token, until)
  922. proc parseWhile*(s: string, token: var string, validChars: set[char],
  923. start = 0): int {.inline.} =
  924. ## Parses a token and stores it in ``token``. Returns
  925. ## the number of the parsed characters or 0 in case of an error. A token
  926. ## consists of the characters in `validChars`.
  927. runnableExamples:
  928. var myToken: string
  929. doAssert parseWhile("Hello World", myToken, {'W', 'o', 'r'}, 0) == 0
  930. doAssert myToken.len() == 0
  931. doAssert parseWhile("Hello World", myToken, {'W', 'o', 'r'}, 6) == 3
  932. doAssert myToken == "Wor"
  933. parseWhile(s.toOpenArray(start, s.high), token, validChars)
  934. proc captureBetween*(s: string, first: char, second = '\0', start = 0): string =
  935. ## Finds the first occurrence of ``first``, then returns everything from there
  936. ## up to ``second`` (if ``second`` is '\0', then ``first`` is used).
  937. runnableExamples:
  938. doAssert captureBetween("Hello World", 'e') == "llo World"
  939. doAssert captureBetween("Hello World", 'e', 'r') == "llo Wo"
  940. doAssert captureBetween("Hello World", 'l', start = 6) == "d"
  941. captureBetween(s.toOpenArray(start, s.high), first, second)
  942. proc parseBiggestInt*(s: string, number: var BiggestInt, start = 0): int {.noSideEffect, raises: [ValueError].} =
  943. ## Parses an integer starting at `start` and stores the value into `number`.
  944. ## Result is the number of processed chars or 0 if there is no integer.
  945. ## `ValueError` is raised if the parsed integer is out of the valid range.
  946. runnableExamples:
  947. var res: BiggestInt
  948. doAssert parseBiggestInt("9223372036854775807", res, 0) == 19
  949. doAssert res == 9223372036854775807
  950. doAssert parseBiggestInt("-2024_05_09", res) == 11
  951. doAssert res == -20240509
  952. doAssert parseBiggestInt("-2024_05_02", res, 7) == 4
  953. doAssert res == 502
  954. parseBiggestInt(s.toOpenArray(start, s.high), number)
  955. proc parseInt*(s: string, number: var int, start = 0): int {.noSideEffect, raises: [ValueError].} =
  956. ## Parses an integer starting at `start` and stores the value into `number`.
  957. ## Result is the number of processed chars or 0 if there is no integer.
  958. ## `ValueError` is raised if the parsed integer is out of the valid range.
  959. runnableExamples:
  960. var res: int
  961. doAssert parseInt("-2024_05_02", res) == 11
  962. doAssert res == -20240502
  963. doAssert parseInt("-2024_05_02", res, 7) == 4
  964. doAssert res == 502
  965. parseInt(s.toOpenArray(start, s.high), number)
  966. proc parseSaturatedNatural*(s: string, b: var int, start = 0): int {.
  967. raises: [].} =
  968. ## Parses a natural number into ``b``. This cannot raise an overflow
  969. ## error. ``high(int)`` is returned for an overflow.
  970. ## The number of processed character is returned.
  971. ## This is usually what you really want to use instead of `parseInt`:idx:.
  972. runnableExamples:
  973. var res = 0
  974. discard parseSaturatedNatural("848", res)
  975. doAssert res == 848
  976. parseSaturatedNatural(s.toOpenArray(start, s.high), b)
  977. proc parseBiggestUInt*(s: string, number: var BiggestUInt, start = 0): int {.noSideEffect, raises: [ValueError].} =
  978. ## Parses an unsigned integer starting at `start` and stores the value
  979. ## into `number`.
  980. ## `ValueError` is raised if the parsed integer is out of the valid range.
  981. runnableExamples:
  982. var res: BiggestUInt
  983. doAssert parseBiggestUInt("12", res, 0) == 2
  984. doAssert res == 12
  985. doAssert parseBiggestUInt("1111111111111111111", res, 0) == 19
  986. doAssert res == 1111111111111111111'u64
  987. parseBiggestUInt(s.toOpenArray(start, s.high), number)
  988. proc parseUInt*(s: string, number: var uint, start = 0): int {.noSideEffect, raises: [ValueError].} =
  989. ## Parses an unsigned integer starting at `start` and stores the value
  990. ## into `number`.
  991. ## `ValueError` is raised if the parsed integer is out of the valid range.
  992. runnableExamples:
  993. var res: uint
  994. doAssert parseUInt("3450", res) == 4
  995. doAssert res == 3450
  996. doAssert parseUInt("3450", res, 2) == 2
  997. doAssert res == 50
  998. parseUInt(s.toOpenArray(start, s.high), number)
  999. proc parseBiggestFloat*(s: string, number: var BiggestFloat, start = 0): int {.noSideEffect.} =
  1000. ## Parses a float starting at `start` and stores the value into `number`.
  1001. ## Result is the number of processed chars or 0 if a parsing error
  1002. ## occurred.
  1003. parseFloat(s.toOpenArray(start, s.high), number)
  1004. proc parseFloat*(s: string, number: var float, start = 0): int {.noSideEffect.} =
  1005. ## Parses a float starting at `start` and stores the value into `number`.
  1006. ## Result is the number of processed chars or 0 if there occurred a parsing
  1007. ## error.
  1008. runnableExamples:
  1009. var res: float
  1010. doAssert parseFloat("32", res, 0) == 2
  1011. doAssert res == 32.0
  1012. doAssert parseFloat("32.57", res, 0) == 5
  1013. doAssert res == 32.57
  1014. doAssert parseFloat("32.57", res, 3) == 2
  1015. doAssert res == 57.00
  1016. parseFloat(s.toOpenArray(start, s.high), number)
  1017. iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind,
  1018. value: string] =
  1019. ## Tokenizes the string `s` into substrings for interpolation purposes.
  1020. ##
  1021. runnableExamples:
  1022. var outp: seq[tuple[kind: InterpolatedKind, value: string]]
  1023. for k, v in interpolatedFragments(" $this is ${an example} $$"):
  1024. outp.add (k, v)
  1025. doAssert outp == @[(ikStr, " "),
  1026. (ikVar, "this"),
  1027. (ikStr, " is "),
  1028. (ikExpr, "an example"),
  1029. (ikStr, " "),
  1030. (ikDollar, "$")]
  1031. for x in s.toOa.interpolatedFragments:
  1032. yield x