parseutils.nim 43 KB

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