strconv.odin 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705
  1. package strconv
  2. import "core:unicode/utf8"
  3. import "decimal"
  4. /*
  5. Parses a boolean value from the input string
  6. **Inputs**
  7. - s: The input string
  8. - true: "1", "t", "T", "true", "TRUE", "True"
  9. - false: "0", "f", "F", "false", "FALSE", "False"
  10. - n: An optional pointer to an int to store the length of the parsed substring (default: nil)
  11. **Returns**
  12. - result: The parsed boolean value (default: false)
  13. - ok: A boolean indicating whether the parsing was successful
  14. */
  15. parse_bool :: proc(s: string, n: ^int = nil) -> (result: bool = false, ok: bool) {
  16. switch s {
  17. case "1", "t", "T", "true", "TRUE", "True":
  18. if n != nil { n^ = len(s) }
  19. return true, true
  20. case "0", "f", "F", "false", "FALSE", "False":
  21. if n != nil { n^ = len(s) }
  22. return false, true
  23. }
  24. return
  25. }
  26. /*
  27. Finds the integer value of the given rune
  28. **Inputs**
  29. - r: The input rune to find the integer value of
  30. **Returns** The integer value of the given rune
  31. */
  32. _digit_value :: proc(r: rune) -> int {
  33. ri := int(r)
  34. v: int = 16
  35. switch r {
  36. case '0'..='9': v = ri-'0'
  37. case 'a'..='z': v = ri-'a'+10
  38. case 'A'..='Z': v = ri-'A'+10
  39. }
  40. return v
  41. }
  42. /*
  43. Parses an integer value from the input string in the given base, without a prefix
  44. **Inputs**
  45. - str: The input string to parse the integer value from
  46. - base: The base of the integer value to be parsed (must be between 1 and 16)
  47. - n: An optional pointer to an int to store the length of the parsed substring (default: nil)
  48. Example:
  49. import "core:fmt"
  50. import "core:strconv"
  51. parse_i64_of_base_example :: proc() {
  52. n, ok := strconv.parse_i64_of_base("-1234e3", 10)
  53. fmt.println(n, ok)
  54. }
  55. Output:
  56. -1234 false
  57. **Returns**
  58. - value: Parses an integer value from a string, in the given base, without a prefix.
  59. - ok: ok=false if no numeric value of the appropriate base could be found, or if the input string contained more than just the number.
  60. */
  61. parse_i64_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: i64, ok: bool) {
  62. assert(base <= 16, "base must be 1-16")
  63. s := str
  64. defer if n != nil { n^ = len(str)-len(s) }
  65. if s == "" {
  66. return
  67. }
  68. neg := false
  69. if len(s) > 1 {
  70. switch s[0] {
  71. case '-':
  72. neg = true
  73. s = s[1:]
  74. case '+':
  75. s = s[1:]
  76. }
  77. }
  78. i := 0
  79. for r in s {
  80. if r == '_' {
  81. i += 1
  82. continue
  83. }
  84. v := i64(_digit_value(r))
  85. if v >= i64(base) {
  86. break
  87. }
  88. value *= i64(base)
  89. value += v
  90. i += 1
  91. }
  92. s = s[i:]
  93. if neg {
  94. value = -value
  95. }
  96. ok = len(s) == 0
  97. return
  98. }
  99. /*
  100. Parses an integer value from the input string in base 10, unless there's a prefix
  101. **Inputs**
  102. - str: The input string to parse the integer value from
  103. - n: An optional pointer to an int to store the length of the parsed substring (default: nil)
  104. Example:
  105. import "core:fmt"
  106. import "core:strconv"
  107. parse_i64_maybe_prefixed_example :: proc() {
  108. n, ok := strconv.parse_i64_maybe_prefixed("1234")
  109. fmt.println(n,ok)
  110. n, ok = strconv.parse_i64_maybe_prefixed("0xeeee")
  111. fmt.println(n,ok)
  112. }
  113. Output:
  114. 1234 true
  115. 61166 true
  116. **Returns**
  117. - value: The parsed integer value
  118. - ok: ok=false if a valid integer could not be found, or if the input string contained more than just the number.
  119. */
  120. parse_i64_maybe_prefixed :: proc(str: string, n: ^int = nil) -> (value: i64, ok: bool) {
  121. s := str
  122. defer if n != nil { n^ = len(str)-len(s) }
  123. if s == "" {
  124. return
  125. }
  126. neg := false
  127. if len(s) > 1 {
  128. switch s[0] {
  129. case '-':
  130. neg = true
  131. s = s[1:]
  132. case '+':
  133. s = s[1:]
  134. }
  135. }
  136. base: i64 = 10
  137. if len(s) > 2 && s[0] == '0' {
  138. switch s[1] {
  139. case 'b': base = 2; s = s[2:]
  140. case 'o': base = 8; s = s[2:]
  141. case 'd': base = 10; s = s[2:]
  142. case 'z': base = 12; s = s[2:]
  143. case 'x': base = 16; s = s[2:]
  144. }
  145. }
  146. i := 0
  147. for r in s {
  148. if r == '_' {
  149. i += 1
  150. continue
  151. }
  152. v := i64(_digit_value(r))
  153. if v >= base {
  154. break
  155. }
  156. value *= base
  157. value += v
  158. i += 1
  159. }
  160. s = s[i:]
  161. if neg {
  162. value = -value
  163. }
  164. ok = len(s) == 0
  165. return
  166. }
  167. //
  168. parse_i64 :: proc{parse_i64_maybe_prefixed, parse_i64_of_base}
  169. /*
  170. Parses an unsigned 64-bit integer value from the input string without a prefix, using the specified base
  171. **Inputs**
  172. - str: The input string to parse
  173. - base: The base of the number system to use for parsing
  174. - Must be between 1 and 16 (inclusive)
  175. - n: An optional pointer to an int to store the length of the parsed substring (default: nil)
  176. Example:
  177. import "core:fmt"
  178. import "core:strconv"
  179. parse_u64_of_base_example :: proc() {
  180. n, ok := strconv.parse_u64_of_base("1234e3", 10)
  181. fmt.println(n,ok)
  182. n, ok = strconv.parse_u64_of_base("5678eee",16)
  183. fmt.println(n,ok)
  184. }
  185. Output:
  186. 1234 false
  187. 90672878 true
  188. **Returns**
  189. - value: The parsed uint64 value
  190. - ok: A boolean indicating whether the parsing was successful
  191. */
  192. parse_u64_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: u64, ok: bool) {
  193. assert(base <= 16, "base must be 1-16")
  194. s := str
  195. defer if n != nil { n^ = len(str)-len(s) }
  196. if s == "" {
  197. return
  198. }
  199. if len(s) > 1 && s[0] == '+' {
  200. s = s[1:]
  201. }
  202. i := 0
  203. for r in s {
  204. if r == '_' {
  205. i += 1
  206. continue
  207. }
  208. v := u64(_digit_value(r))
  209. if v >= u64(base) {
  210. break
  211. }
  212. value *= u64(base)
  213. value += v
  214. i += 1
  215. }
  216. s = s[i:]
  217. ok = len(s) == 0
  218. return
  219. }
  220. /*
  221. Parses an unsigned 64-bit integer value from the input string, using the specified base or inferring the base from a prefix
  222. **Inputs**
  223. - str: The input string to parse
  224. - base: The base of the number system to use for parsing (default: 0)
  225. - If base is 0, it will be inferred based on the prefix in the input string (e.g. '0x' for hexadecimal)
  226. - If base is not 0, it will be used for parsing regardless of any prefix in the input string
  227. - n: An optional pointer to an int to store the length of the parsed substring (default: nil)
  228. Example:
  229. import "core:fmt"
  230. import "core:strconv"
  231. parse_u64_maybe_prefixed_example :: proc() {
  232. n, ok := strconv.parse_u64_maybe_prefixed("1234")
  233. fmt.println(n,ok)
  234. n, ok = strconv.parse_u64_maybe_prefixed("0xee")
  235. fmt.println(n,ok)
  236. }
  237. Output:
  238. 1234 true
  239. 238 true
  240. **Returns**
  241. - value: The parsed uint64 value
  242. - ok: ok=false if a valid integer could not be found, if the value was negative, or if the input string contained more than just the number.
  243. */
  244. parse_u64_maybe_prefixed :: proc(str: string, n: ^int = nil) -> (value: u64, ok: bool) {
  245. s := str
  246. defer if n != nil { n^ = len(str)-len(s) }
  247. if s == "" {
  248. return
  249. }
  250. if len(s) > 1 && s[0] == '+' {
  251. s = s[1:]
  252. }
  253. base := u64(10)
  254. if len(s) > 2 && s[0] == '0' {
  255. switch s[1] {
  256. case 'b': base = 2; s = s[2:]
  257. case 'o': base = 8; s = s[2:]
  258. case 'd': base = 10; s = s[2:]
  259. case 'z': base = 12; s = s[2:]
  260. case 'x': base = 16; s = s[2:]
  261. }
  262. }
  263. i := 0
  264. for r in s {
  265. if r == '_' {
  266. i += 1
  267. continue
  268. }
  269. v := u64(_digit_value(r))
  270. if v >= base {
  271. break
  272. }
  273. value *= base
  274. value += v
  275. i += 1
  276. }
  277. s = s[i:]
  278. ok = len(s) == 0
  279. return
  280. }
  281. //
  282. parse_u64 :: proc{parse_u64_maybe_prefixed, parse_u64_of_base}
  283. /*
  284. Parses a signed integer value from the input string, using the specified base or inferring the base from a prefix
  285. **Inputs**
  286. - s: The input string to parse
  287. - base: The base of the number system to use for parsing (default: 0)
  288. - If base is 0, it will be inferred based on the prefix in the input string (e.g. '0x' for hexadecimal)
  289. - If base is not 0, it will be used for parsing regardless of any prefix in the input string
  290. Example:
  291. import "core:fmt"
  292. import "core:strconv"
  293. parse_int_example :: proc() {
  294. n, ok := strconv.parse_int("1234") // without prefix, inferred base 10
  295. fmt.println(n,ok)
  296. n, ok = strconv.parse_int("ffff", 16) // without prefix, explicit base
  297. fmt.println(n,ok)
  298. n, ok = strconv.parse_int("0xffff") // with prefix and inferred base
  299. fmt.println(n,ok)
  300. }
  301. Output:
  302. 1234 true
  303. 65535 true
  304. 65535 true
  305. **Returns**
  306. - value: The parsed int value
  307. - ok: `false` if no appropriate value could be found, or if the input string contained more than just the number.
  308. */
  309. parse_int :: proc(s: string, base := 0, n: ^int = nil) -> (value: int, ok: bool) {
  310. v: i64 = ---
  311. switch base {
  312. case 0: v, ok = parse_i64_maybe_prefixed(s, n)
  313. case: v, ok = parse_i64_of_base(s, base, n)
  314. }
  315. value = int(v)
  316. return
  317. }
  318. /*
  319. Parses an unsigned integer value from the input string, using the specified base or inferring the base from a prefix
  320. **Inputs**
  321. - s: The input string to parse
  322. - base: The base of the number system to use for parsing (default: 0, inferred)
  323. - If base is 0, it will be inferred based on the prefix in the input string (e.g. '0x' for hexadecimal)
  324. - If base is not 0, it will be used for parsing regardless of any prefix in the input string
  325. Example:
  326. import "core:fmt"
  327. import "core:strconv"
  328. parse_uint_example :: proc() {
  329. n, ok := strconv.parse_uint("1234") // without prefix, inferred base 10
  330. fmt.println(n,ok)
  331. n, ok = strconv.parse_uint("ffff", 16) // without prefix, explicit base
  332. fmt.println(n,ok)
  333. n, ok = strconv.parse_uint("0xffff") // with prefix and inferred base
  334. fmt.println(n,ok)
  335. }
  336. Output:
  337. 1234 true
  338. 65535 true
  339. 65535 true
  340. **Returns**
  341. value: The parsed uint value
  342. ok: `false` if no appropriate value could be found; the value was negative; he input string contained more than just the number
  343. */
  344. parse_uint :: proc(s: string, base := 0, n: ^int = nil) -> (value: uint, ok: bool) {
  345. v: u64 = ---
  346. switch base {
  347. case 0: v, ok = parse_u64_maybe_prefixed(s, n)
  348. case: v, ok = parse_u64_of_base(s, base, n)
  349. }
  350. value = uint(v)
  351. return
  352. }
  353. /*
  354. Parses an integer value from a string in the given base, without any prefix
  355. **Inputs**
  356. - str: The input string containing the integer value
  357. - base: The base (radix) to use for parsing the integer (1-16)
  358. - n: An optional pointer to an int to store the length of the parsed substring (default: nil)
  359. Example:
  360. import "core:fmt"
  361. import "core:strconv"
  362. parse_i128_of_base_example :: proc() {
  363. n, ok := strconv.parse_i128_of_base("-1234eeee", 10)
  364. fmt.println(n,ok)
  365. }
  366. Output:
  367. -1234 false
  368. **Returns**
  369. - value: The parsed i128 value
  370. - ok: false if no numeric value of the appropriate base could be found, or if the input string contained more than just the number.
  371. */
  372. parse_i128_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: i128, ok: bool) {
  373. assert(base <= 16, "base must be 1-16")
  374. s := str
  375. defer if n != nil { n^ = len(str)-len(s) }
  376. if s == "" {
  377. return
  378. }
  379. neg := false
  380. if len(s) > 1 {
  381. switch s[0] {
  382. case '-':
  383. neg = true
  384. s = s[1:]
  385. case '+':
  386. s = s[1:]
  387. }
  388. }
  389. i := 0
  390. for r in s {
  391. if r == '_' {
  392. i += 1
  393. continue
  394. }
  395. v := i128(_digit_value(r))
  396. if v >= i128(base) {
  397. break
  398. }
  399. value *= i128(base)
  400. value += v
  401. i += 1
  402. }
  403. s = s[i:]
  404. if neg {
  405. value = -value
  406. }
  407. ok = len(s) == 0
  408. return
  409. }
  410. /*
  411. Parses an integer value from a string in base 10, unless there's a prefix
  412. **Inputs**
  413. - str: The input string containing the integer value
  414. - n: An optional pointer to an int to store the length of the parsed substring (default: nil)
  415. Example:
  416. import "core:fmt"
  417. import "core:strconv"
  418. parse_i128_maybe_prefixed_example :: proc() {
  419. n, ok := strconv.parse_i128_maybe_prefixed("1234")
  420. fmt.println(n, ok)
  421. n, ok = strconv.parse_i128_maybe_prefixed("0xeeee")
  422. fmt.println(n, ok)
  423. }
  424. Output:
  425. 1234 true
  426. 61166 true
  427. **Returns**
  428. - value: The parsed i128 value
  429. - ok: `false` if a valid integer could not be found, or if the input string contained more than just the number.
  430. */
  431. parse_i128_maybe_prefixed :: proc(str: string, n: ^int = nil) -> (value: i128, ok: bool) {
  432. s := str
  433. defer if n != nil { n^ = len(str)-len(s) }
  434. if s == "" {
  435. return
  436. }
  437. neg := false
  438. if len(s) > 1 {
  439. switch s[0] {
  440. case '-':
  441. neg = true
  442. s = s[1:]
  443. case '+':
  444. s = s[1:]
  445. }
  446. }
  447. base: i128 = 10
  448. if len(s) > 2 && s[0] == '0' {
  449. switch s[1] {
  450. case 'b': base = 2; s = s[2:]
  451. case 'o': base = 8; s = s[2:]
  452. case 'd': base = 10; s = s[2:]
  453. case 'z': base = 12; s = s[2:]
  454. case 'x': base = 16; s = s[2:]
  455. }
  456. }
  457. i := 0
  458. for r in s {
  459. if r == '_' {
  460. i += 1
  461. continue
  462. }
  463. v := i128(_digit_value(r))
  464. if v >= base {
  465. break
  466. }
  467. value *= base
  468. value += v
  469. i += 1
  470. }
  471. s = s[i:]
  472. if neg {
  473. value = -value
  474. }
  475. ok = len(s) == 0
  476. return
  477. }
  478. //
  479. parse_i128 :: proc{parse_i128_maybe_prefixed, parse_i128_of_base}
  480. /*
  481. Parses an unsigned integer value from a string in the given base, without any prefix
  482. **Inputs**
  483. - str: The input string containing the integer value
  484. - base: The base (radix) to use for parsing the integer (1-16)
  485. - n: An optional pointer to an int to store the length of the parsed substring (default: nil)
  486. Example:
  487. import "core:fmt"
  488. import "core:strconv"
  489. parse_u128_of_base_example :: proc() {
  490. n, ok := strconv.parse_u128_of_base("1234eeee", 10)
  491. fmt.println(n, ok)
  492. n, ok = strconv.parse_u128_of_base("5678eeee", 16)
  493. fmt.println(n, ok)
  494. }
  495. Output:
  496. 1234 false
  497. 1450766062 true
  498. **Returns**
  499. - value: The parsed u128 value
  500. - ok: `false` if no numeric value of the appropriate base could be found, or if the input string contained more than just the number.
  501. */
  502. parse_u128_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: u128, ok: bool) {
  503. assert(base <= 16, "base must be 1-16")
  504. s := str
  505. defer if n != nil { n^ = len(str)-len(s) }
  506. if s == "" {
  507. return
  508. }
  509. if len(s) > 1 && s[0] == '+' {
  510. s = s[1:]
  511. }
  512. i := 0
  513. for r in s {
  514. if r == '_' {
  515. i += 1
  516. continue
  517. }
  518. v := u128(_digit_value(r))
  519. if v >= u128(base) {
  520. break
  521. }
  522. value *= u128(base)
  523. value += v
  524. i += 1
  525. }
  526. s = s[i:]
  527. ok = len(s) == 0
  528. return
  529. }
  530. /*
  531. Parses an unsigned integer value from a string in base 10, unless there's a prefix
  532. **Inputs**
  533. - str: The input string containing the integer value
  534. - n: An optional pointer to an int to store the length of the parsed substring (default: nil)
  535. Example:
  536. import "core:fmt"
  537. import "core:strconv"
  538. parse_u128_maybe_prefixed_example :: proc() {
  539. n, ok := strconv.parse_u128_maybe_prefixed("1234")
  540. fmt.println(n, ok)
  541. n, ok = strconv.parse_u128_maybe_prefixed("5678eeee")
  542. fmt.println(n, ok)
  543. }
  544. Output:
  545. 1234 true
  546. 5678 false
  547. **Returns**
  548. - value: The parsed u128 value
  549. - ok: false if a valid integer could not be found, if the value was negative, or if the input string contained more than just the number.
  550. */
  551. parse_u128_maybe_prefixed :: proc(str: string, n: ^int = nil) -> (value: u128, ok: bool) {
  552. s := str
  553. defer if n != nil { n^ = len(str)-len(s) }
  554. if s == "" {
  555. return
  556. }
  557. if len(s) > 1 && s[0] == '+' {
  558. s = s[1:]
  559. }
  560. base := u128(10)
  561. if len(s) > 2 && s[0] == '0' {
  562. switch s[1] {
  563. case 'b': base = 2; s = s[2:]
  564. case 'o': base = 8; s = s[2:]
  565. case 'd': base = 10; s = s[2:]
  566. case 'z': base = 12; s = s[2:]
  567. case 'x': base = 16; s = s[2:]
  568. }
  569. }
  570. i := 0
  571. for r in s {
  572. if r == '_' {
  573. i += 1
  574. continue
  575. }
  576. v := u128(_digit_value(r))
  577. if v >= base {
  578. break
  579. }
  580. value *= base
  581. value += v
  582. i += 1
  583. }
  584. s = s[i:]
  585. ok = len(s) == 0
  586. return
  587. }
  588. //
  589. parse_u128 :: proc{parse_u128_maybe_prefixed, parse_u128_of_base}
  590. /*
  591. Converts a byte to lowercase
  592. **Inputs**
  593. - ch: A byte character to be converted to lowercase.
  594. **Returns**
  595. - A lowercase byte character.
  596. */
  597. @(private)
  598. lower :: #force_inline proc "contextless" (ch: byte) -> byte { return ('a' - 'A') | ch }
  599. /*
  600. Parses a 32-bit floating point number from a string
  601. **Inputs**
  602. - s: The input string containing a 32-bit floating point number.
  603. - n: An optional pointer to an int to store the length of the parsed substring (default: nil).
  604. Example:
  605. import "core:fmt"
  606. import "core:strconv"
  607. parse_f32_example :: proc() {
  608. n, ok := strconv.parse_f32("1234eee")
  609. fmt.printfln("%.3f %v", n, ok)
  610. n, ok = strconv.parse_f32("5678e2")
  611. fmt.printfln("%.3f %v", n, ok)
  612. }
  613. Output:
  614. 0.000 false
  615. 567800.000 true
  616. **Returns**
  617. - value: The parsed 32-bit floating point number.
  618. - ok: `false` if a base 10 float could not be found, or if the input string contained more than just the number.
  619. */
  620. parse_f32 :: proc(s: string, n: ^int = nil) -> (value: f32, ok: bool) {
  621. v: f64 = ---
  622. v, ok = parse_f64(s, n)
  623. return f32(v), ok
  624. }
  625. /*
  626. Parses a 64-bit floating point number from a string
  627. **Inputs**
  628. - str: The input string containing a 64-bit floating point number.
  629. - n: An optional pointer to an int to store the length of the parsed substring (default: nil).
  630. Example:
  631. import "core:fmt"
  632. import "core:strconv"
  633. parse_f64_example :: proc() {
  634. n, ok := strconv.parse_f64("1234eee")
  635. fmt.printfln("%.3f %v", n, ok)
  636. n, ok = strconv.parse_f64("5678e2")
  637. fmt.printfln("%.3f %v", n, ok)
  638. }
  639. Output:
  640. 0.000 false
  641. 567800.000 true
  642. **Returns**
  643. - value: The parsed 64-bit floating point number.
  644. - ok: `false` if a base 10 float could not be found, or if the input string contained more than just the number.
  645. */
  646. parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
  647. nr: int
  648. value, nr, ok = parse_f64_prefix(str)
  649. if ok && len(str) != nr {
  650. ok = false
  651. }
  652. if n != nil { n^ = nr }
  653. return
  654. }
  655. /*
  656. Parses a 32-bit floating point number from a string and returns the parsed number, the length of the parsed substring, and a boolean indicating whether the parsing was successful
  657. **Inputs**
  658. - str: The input string containing a 32-bit floating point number.
  659. Example:
  660. import "core:fmt"
  661. import "core:strconv"
  662. parse_f32_prefix_example :: proc() {
  663. n, _, ok := strconv.parse_f32_prefix("1234eee")
  664. fmt.printfln("%.3f %v", n, ok)
  665. n, _, ok = strconv.parse_f32_prefix("5678e2")
  666. fmt.printfln("%.3f %v", n, ok)
  667. }
  668. Output:
  669. 0.000 false
  670. 567800.000 true
  671. **Returns**
  672. - value: The parsed 32-bit floating point number.
  673. - nr: The length of the parsed substring.
  674. - ok: A boolean indicating whether the parsing was successful.
  675. */
  676. parse_f32_prefix :: proc(str: string) -> (value: f32, nr: int, ok: bool) {
  677. f: f64
  678. f, nr, ok = parse_f64_prefix(str)
  679. value = f32(f)
  680. return
  681. }
  682. /*
  683. Parses a 64-bit floating point number from a string and returns the parsed number, the length of the parsed substring, and a boolean indicating whether the parsing was successful
  684. **Inputs**
  685. - str: The input string containing a 64-bit floating point number.
  686. Example:
  687. import "core:fmt"
  688. import "core:strconv"
  689. parse_f64_prefix_example :: proc() {
  690. n, _, ok := strconv.parse_f64_prefix("12.34eee")
  691. fmt.printfln("%.3f %v", n, ok)
  692. n, _, ok = strconv.parse_f64_prefix("12.34e2")
  693. fmt.printfln("%.3f %v", n, ok)
  694. }
  695. Output:
  696. 0.000 false
  697. 1234.000 true
  698. **Returns**
  699. - value: The parsed 64-bit floating point number.
  700. - nr: The length of the parsed substring.
  701. - ok: `false` if a base 10 float could not be found, or if the input string contained more than just the number.
  702. */
  703. parse_f64_prefix :: proc(str: string) -> (value: f64, nr: int, ok: bool) {
  704. common_prefix_len_ignore_case :: proc "contextless" (s, prefix: string) -> int {
  705. n := len(prefix)
  706. if n > len(s) {
  707. n = len(s)
  708. }
  709. for i in 0..<n {
  710. c := s[i]
  711. if 'A' <= c && c <= 'Z' {
  712. c += 'a' - 'A'
  713. }
  714. if c != prefix[i] {
  715. return i
  716. }
  717. }
  718. return n
  719. }
  720. check_special :: proc "contextless" (s: string) -> (f: f64, n: int, ok: bool) {
  721. s := s
  722. if len(s) > 0 {
  723. sign := 1
  724. nsign := 0
  725. switch s[0] {
  726. case '+', '-':
  727. if s[0] == '-' {
  728. sign = -1
  729. }
  730. nsign = 1
  731. s = s[1:]
  732. fallthrough
  733. case 'i', 'I':
  734. n = common_prefix_len_ignore_case(s, "infinity")
  735. if 3 < n && n < 8 { // "inf" or "infinity"
  736. n = 3
  737. }
  738. if n == 3 || n == 8 {
  739. f = 0h7ff00000_00000000 if sign == 1 else 0hfff00000_00000000
  740. n = nsign + 3
  741. ok = true
  742. return
  743. }
  744. case 'n', 'N':
  745. if common_prefix_len_ignore_case(s, "nan") == 3 {
  746. f = 0h7ff80000_00000001
  747. n = nsign + 3
  748. ok = true
  749. return
  750. }
  751. }
  752. }
  753. return
  754. }
  755. parse_components :: proc "contextless" (s: string) -> (mantissa: u64, exp: int, neg, trunc, hex: bool, i: int, ok: bool) {
  756. if len(s) == 0 {
  757. return
  758. }
  759. switch s[i] {
  760. case '+': i += 1
  761. case '-': i += 1; neg = true
  762. }
  763. base := u64(10)
  764. MAX_MANT_DIGITS := 19
  765. exp_char := byte('e')
  766. // support stupid 0x1.ABp100 hex floats even if Odin doesn't
  767. if i+2 < len(s) && s[i] == '0' && lower(s[i+1]) == 'x' {
  768. base = 16
  769. MAX_MANT_DIGITS = 16
  770. i += 2
  771. exp_char = 'p'
  772. hex = true
  773. }
  774. underscores := false
  775. saw_dot, saw_digits := false, false
  776. nd := 0
  777. nd_mant := 0
  778. decimal_point := 0
  779. loop: for ; i < len(s); i += 1 {
  780. switch c := s[i]; true {
  781. case c == '_':
  782. underscores = true
  783. continue loop
  784. case c == '.':
  785. if saw_dot {
  786. break loop
  787. }
  788. saw_dot = true
  789. decimal_point = nd
  790. continue loop
  791. case '0' <= c && c <= '9':
  792. saw_digits = true
  793. if c == '0' && nd == 0 {
  794. decimal_point -= 1
  795. continue loop
  796. }
  797. nd += 1
  798. if nd_mant < MAX_MANT_DIGITS {
  799. mantissa *= base
  800. mantissa += u64(c - '0')
  801. nd_mant += 1
  802. } else if c != '0' {
  803. trunc = true
  804. }
  805. continue loop
  806. case base == 16 && 'a' <= lower(c) && lower(c) <= 'f':
  807. saw_digits = true
  808. nd += 1
  809. if nd_mant < MAX_MANT_DIGITS {
  810. mantissa *= 16
  811. mantissa += u64(lower(c) - 'a' + 10)
  812. nd_mant += 1
  813. } else {
  814. trunc = true
  815. }
  816. continue loop
  817. }
  818. break loop
  819. }
  820. if !saw_digits {
  821. return
  822. }
  823. if !saw_dot {
  824. decimal_point = nd
  825. }
  826. if base == 16 {
  827. decimal_point *= 4
  828. nd_mant *= 4
  829. }
  830. if i < len(s) && lower(s[i]) == exp_char {
  831. i += 1
  832. if i >= len(s) { return }
  833. exp_sign := 1
  834. switch s[i] {
  835. case '+': i += 1
  836. case '-': i += 1; exp_sign = -1
  837. }
  838. if i >= len(s) || s[i] < '0' || s[i] > '9' {
  839. return
  840. }
  841. e := 0
  842. for ; i < len(s) && ('0' <= s[i] && s[i] <= '9' || s[i] == '_'); i += 1 {
  843. if s[i] == '_' {
  844. underscores = true
  845. continue
  846. }
  847. if e < 1e5 {
  848. e = e*10 + int(s[i]) - '0'
  849. }
  850. }
  851. decimal_point += e * exp_sign
  852. } else if base == 16 {
  853. return
  854. }
  855. if mantissa != 0 {
  856. exp = decimal_point - nd_mant
  857. }
  858. ok = true
  859. return
  860. }
  861. parse_hex :: proc "contextless" (s: string, mantissa: u64, exp: int, neg, trunc: bool) -> (f64, bool) {
  862. info := &_f64_info
  863. mantissa, exp := mantissa, exp
  864. MAX_EXP := 1<<info.expbits + info.bias - 2
  865. MIN_EXP := info.bias + 1
  866. exp += int(info.mantbits)
  867. for mantissa != 0 && mantissa >> (info.mantbits+2) == 0 {
  868. mantissa <<= 1
  869. exp -= 1
  870. }
  871. if trunc {
  872. mantissa |= 1
  873. }
  874. for mantissa != 0 && mantissa >> (info.mantbits+2) == 0 {
  875. mantissa = mantissa>>1 | mantissa&1
  876. exp += 1
  877. }
  878. // denormalize
  879. if mantissa > 1 && exp < MIN_EXP-2 {
  880. mantissa = mantissa>>1 | mantissa&1
  881. exp += 1
  882. }
  883. round := mantissa & 3
  884. mantissa >>= 2
  885. round |= mantissa & 1 // round to even
  886. exp += 2
  887. if round == 3 {
  888. mantissa += 1
  889. if mantissa == 1 << (1 + info.mantbits) {
  890. mantissa >>= 1
  891. exp += 1
  892. }
  893. }
  894. if mantissa>>info.mantbits == 0 {
  895. // zero or denormal
  896. exp = info.bias
  897. }
  898. ok := true
  899. if exp > MAX_EXP {
  900. // infinity or invalid
  901. mantissa = 1<<info.mantbits
  902. exp = MAX_EXP + 1
  903. ok = false
  904. }
  905. bits := mantissa & (1<<info.mantbits - 1)
  906. bits |= u64((exp-info.bias) & (1<<info.expbits - 1)) << info.mantbits
  907. if neg {
  908. bits |= 1 << info.mantbits << info.expbits
  909. }
  910. return transmute(f64)bits, ok
  911. }
  912. if value, nr, ok = check_special(str); ok {
  913. return
  914. }
  915. mantissa: u64
  916. exp: int
  917. neg, trunc, hex: bool
  918. mantissa, exp, neg, trunc, hex, nr = parse_components(str) or_return
  919. if hex {
  920. value, ok = parse_hex(str, mantissa, exp, neg, trunc)
  921. return
  922. }
  923. trunc_block: if !trunc {
  924. @static pow10 := [?]f64{
  925. 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
  926. 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
  927. 1e20, 1e21, 1e22,
  928. }
  929. if mantissa>>_f64_info.mantbits != 0 {
  930. break trunc_block
  931. }
  932. f := f64(mantissa)
  933. if neg {
  934. f = -f
  935. }
  936. switch {
  937. case exp == 0:
  938. return f, nr, true
  939. case exp > 0 && exp <= 15+22:
  940. if exp > 22 {
  941. f *= pow10[exp-22]
  942. exp = 22
  943. }
  944. if f > 1e15 || f < 1e-15 {
  945. break trunc_block
  946. }
  947. return f * pow10[exp], nr, true
  948. case -22 <= exp && exp < 0:
  949. return f / pow10[-exp], nr, true
  950. }
  951. }
  952. d: decimal.Decimal
  953. decimal.set(&d, str[:nr])
  954. b, overflow := decimal_to_float_bits(&d, &_f64_info)
  955. value = transmute(f64)b
  956. ok = !overflow
  957. return
  958. }
  959. /*
  960. Appends a boolean value as a string to the given buffer
  961. **Inputs**
  962. - buf: The buffer to append the boolean value to
  963. - b: The boolean value to be appended
  964. Example:
  965. import "core:fmt"
  966. import "core:strconv"
  967. append_bool_example :: proc() {
  968. buf: [6]byte
  969. result := strconv.append_bool(buf[:], true)
  970. fmt.println(result, buf)
  971. }
  972. Output:
  973. true [116, 114, 117, 101, 0, 0]
  974. **Returns**
  975. - The resulting string after appending the boolean value
  976. */
  977. append_bool :: proc(buf: []byte, b: bool) -> string {
  978. n := 0
  979. if b {
  980. n = copy(buf, "true")
  981. } else {
  982. n = copy(buf, "false")
  983. }
  984. return string(buf[:n])
  985. }
  986. /*
  987. Appends an unsigned integer value as a string to the given buffer with the specified base
  988. **Inputs**
  989. - buf: The buffer to append the unsigned integer value to
  990. - u: The unsigned integer value to be appended
  991. - base: The base to use for converting the integer value
  992. Example:
  993. import "core:fmt"
  994. import "core:strconv"
  995. append_uint_example :: proc() {
  996. buf: [4]byte
  997. result := strconv.append_uint(buf[:], 42, 16)
  998. fmt.println(result, buf)
  999. }
  1000. Output:
  1001. 2a [50, 97, 0, 0]
  1002. **Returns**
  1003. - The resulting string after appending the unsigned integer value
  1004. */
  1005. append_uint :: proc(buf: []byte, u: u64, base: int) -> string {
  1006. return append_bits(buf, u, base, false, 8*size_of(uint), digits, nil)
  1007. }
  1008. /*
  1009. Appends a signed integer value as a string to the given buffer with the specified base
  1010. **Inputs**
  1011. - buf: The buffer to append the signed integer value to
  1012. - i: The signed integer value to be appended
  1013. - base: The base to use for converting the integer value
  1014. Example:
  1015. import "core:fmt"
  1016. import "core:strconv"
  1017. append_int_example :: proc() {
  1018. buf: [4]byte
  1019. result := strconv.append_int(buf[:], -42, 10)
  1020. fmt.println(result, buf)
  1021. }
  1022. Output:
  1023. -42 [45, 52, 50, 0]
  1024. **Returns**
  1025. - The resulting string after appending the signed integer value
  1026. */
  1027. append_int :: proc(buf: []byte, i: i64, base: int) -> string {
  1028. return append_bits(buf, u64(i), base, true, 8*size_of(int), digits, nil)
  1029. }
  1030. append_u128 :: proc(buf: []byte, u: u128, base: int) -> string {
  1031. return append_bits_128(buf, u, base, false, 8*size_of(uint), digits, nil)
  1032. }
  1033. /*
  1034. Converts an integer value to a string and stores it in the given buffer
  1035. **Inputs**
  1036. - buf: The buffer to store the resulting string
  1037. - i: The integer value to be converted
  1038. Example:
  1039. import "core:fmt"
  1040. import "core:strconv"
  1041. itoa_example :: proc() {
  1042. buf: [4]byte
  1043. result := strconv.itoa(buf[:], 42)
  1044. fmt.println(result, buf) // "42"
  1045. }
  1046. Output:
  1047. 42 [52, 50, 0, 0]
  1048. **Returns**
  1049. - The resulting string after converting the integer value
  1050. */
  1051. itoa :: proc(buf: []byte, i: int) -> string {
  1052. return append_int(buf, i64(i), 10)
  1053. }
  1054. /*
  1055. Converts a string to an integer value
  1056. **Inputs**
  1057. - s: The string to be converted
  1058. Example:
  1059. import "core:fmt"
  1060. import "core:strconv"
  1061. atoi_example :: proc() {
  1062. fmt.println(strconv.atoi("42"))
  1063. }
  1064. Output:
  1065. 42
  1066. **Returns**
  1067. - The resulting integer value
  1068. */
  1069. atoi :: proc(s: string) -> int {
  1070. v, _ := parse_int(s)
  1071. return v
  1072. }
  1073. /*
  1074. Converts a string to a float64 value
  1075. **Inputs**
  1076. - s: The string to be converted
  1077. Example:
  1078. import "core:fmt"
  1079. import "core:strconv"
  1080. atof_example :: proc() {
  1081. fmt.printfln("%.3f", strconv.atof("3.14"))
  1082. }
  1083. Output:
  1084. 3.140
  1085. **Returns**
  1086. - The resulting float64 value after converting the string
  1087. */
  1088. atof :: proc(s: string) -> f64 {
  1089. v, _ := parse_f64(s)
  1090. return v
  1091. }
  1092. // Alias to `append_float`
  1093. ftoa :: append_float
  1094. /*
  1095. Appends a float64 value as a string to the given buffer with the specified format and precision
  1096. **Inputs**
  1097. - buf: The buffer to append the float64 value to
  1098. - f: The float64 value to be appended
  1099. - fmt: The byte specifying the format to use for the conversion
  1100. - prec: The precision to use for the conversion
  1101. - bit_size: The size of the float in bits (32 or 64)
  1102. Example:
  1103. import "core:fmt"
  1104. import "core:strconv"
  1105. append_float_example :: proc() {
  1106. buf: [8]byte
  1107. result := strconv.append_float(buf[:], 3.14159, 'f', 2, 64)
  1108. fmt.println(result, buf)
  1109. }
  1110. Output:
  1111. +3.14 [43, 51, 46, 49, 52, 0, 0, 0]
  1112. **Returns**
  1113. - The resulting string after appending the float
  1114. */
  1115. append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
  1116. return string(generic_ftoa(buf, f, fmt, prec, bit_size))
  1117. }
  1118. /*
  1119. Appends a quoted string representation of the input string to a given byte slice and returns the result as a string
  1120. **Inputs**
  1121. - buf: The byte slice to which the quoted string will be appended
  1122. - str: The input string to be quoted
  1123. !! ISSUE !! NOT EXPECTED -- "\"hello\"" was expected
  1124. Example:
  1125. import "core:fmt"
  1126. import "core:strconv"
  1127. quote_example :: proc() {
  1128. buf: [20]byte
  1129. result := strconv.quote(buf[:], "hello")
  1130. fmt.println(result, buf)
  1131. }
  1132. Output:
  1133. "'h''e''l''l''o'" [34, 39, 104, 39, 39, 101, 39, 39, 108, 39, 39, 108, 39, 39, 111, 39, 34, 0, 0, 0]
  1134. **Returns**
  1135. - The resulting string after appending the quoted string representation
  1136. */
  1137. quote :: proc(buf: []byte, str: string) -> string {
  1138. write_byte :: proc(buf: []byte, i: ^int, bytes: ..byte) {
  1139. if i^ >= len(buf) {
  1140. return
  1141. }
  1142. n := copy(buf[i^:], bytes[:])
  1143. i^ += n
  1144. }
  1145. if buf == nil {
  1146. return ""
  1147. }
  1148. c :: '"'
  1149. i := 0
  1150. s := str
  1151. write_byte(buf, &i, c)
  1152. for width := 0; len(s) > 0; s = s[width:] {
  1153. r := rune(s[0])
  1154. width = 1
  1155. if r >= utf8.RUNE_SELF {
  1156. r, width = utf8.decode_rune_in_string(s)
  1157. }
  1158. if width == 1 && r == utf8.RUNE_ERROR {
  1159. write_byte(buf, &i, '\\', 'x')
  1160. write_byte(buf, &i, digits[s[0]>>4])
  1161. write_byte(buf, &i, digits[s[0]&0xf])
  1162. }
  1163. if i < len(buf) {
  1164. x := quote_rune(buf[i:], r)
  1165. i += len(x)
  1166. }
  1167. }
  1168. write_byte(buf, &i, c)
  1169. return string(buf[:i])
  1170. }
  1171. /*
  1172. Appends a quoted rune representation of the input rune to a given byte slice and returns the result as a string
  1173. **Inputs**
  1174. - buf: The byte slice to which the quoted rune will be appended
  1175. - r: The input rune to be quoted
  1176. Example:
  1177. import "core:fmt"
  1178. import "core:strconv"
  1179. quote_rune_example :: proc() {
  1180. buf: [4]byte
  1181. result := strconv.quote_rune(buf[:], 'A')
  1182. fmt.println(result, buf)
  1183. }
  1184. Output:
  1185. 'A' [39, 65, 39, 0]
  1186. **Returns**
  1187. - The resulting string after appending the quoted rune representation
  1188. */
  1189. quote_rune :: proc(buf: []byte, r: rune) -> string {
  1190. write_byte :: proc(buf: []byte, i: ^int, bytes: ..byte) {
  1191. if i^ < len(buf) {
  1192. n := copy(buf[i^:], bytes[:])
  1193. i^ += n
  1194. }
  1195. }
  1196. write_string :: proc(buf: []byte, i: ^int, s: string) {
  1197. if i^ < len(buf) {
  1198. n := copy(buf[i^:], s)
  1199. i^ += n
  1200. }
  1201. }
  1202. write_rune :: proc(buf: []byte, i: ^int, r: rune) {
  1203. if i^ < len(buf) {
  1204. b, w := utf8.encode_rune(r)
  1205. n := copy(buf[i^:], b[:w])
  1206. i^ += n
  1207. }
  1208. }
  1209. if buf == nil {
  1210. return ""
  1211. }
  1212. i := 0
  1213. write_byte(buf, &i, '\'')
  1214. switch r {
  1215. case '\a': write_string(buf, &i, "\\a")
  1216. case '\b': write_string(buf, &i, "\\b")
  1217. case '\e': write_string(buf, &i, "\\e")
  1218. case '\f': write_string(buf, &i, "\\f")
  1219. case '\n': write_string(buf, &i, "\\n")
  1220. case '\r': write_string(buf, &i, "\\r")
  1221. case '\t': write_string(buf, &i, "\\t")
  1222. case '\v': write_string(buf, &i, "\\v")
  1223. case:
  1224. if r < 32 {
  1225. write_string(buf, &i, "\\x")
  1226. b: [2]byte
  1227. s := append_bits(b[:], u64(r), 16, true, 64, digits, nil)
  1228. switch len(s) {
  1229. case 0: write_string(buf, &i, "00")
  1230. case 1: write_rune(buf, &i, '0')
  1231. case 2: write_string(buf, &i, s)
  1232. }
  1233. } else {
  1234. write_rune(buf, &i, r)
  1235. }
  1236. }
  1237. write_byte(buf, &i, '\'')
  1238. return string(buf[:i])
  1239. }
  1240. /*
  1241. Unquotes a single character from the input string, considering the given quote character
  1242. **Inputs**
  1243. - str: The input string containing the character to unquote
  1244. - quote: The quote character to consider (e.g., '"')
  1245. Example:
  1246. import "core:fmt"
  1247. import "core:strconv"
  1248. unquote_char_example :: proc() {
  1249. src:="\'The\' raven"
  1250. r, multiple_bytes, tail_string, success := strconv.unquote_char(src,'\'')
  1251. fmt.println("Source:", src)
  1252. fmt.printf("r: <%v>, multiple_bytes:%v, tail_string:<%s>, success:%v\n",r, multiple_bytes, tail_string, success)
  1253. }
  1254. Output:
  1255. Source: 'The' raven
  1256. r: <'>, multiple_bytes:false, tail_string:<The' raven>, success:true
  1257. **Returns**
  1258. - r: The unquoted rune
  1259. - multiple_bytes: A boolean indicating if the rune has multiple bytes
  1260. - tail_string: The remaining portion of the input string after unquoting the character
  1261. - success: A boolean indicating whether the unquoting was successful
  1262. */
  1263. unquote_char :: proc(str: string, quote: byte) -> (r: rune, multiple_bytes: bool, tail_string: string, success: bool) {
  1264. hex_to_int :: proc(c: byte) -> int {
  1265. switch c {
  1266. case '0'..='9': return int(c-'0')
  1267. case 'a'..='f': return int(c-'a')+10
  1268. case 'A'..='F': return int(c-'A')+10
  1269. }
  1270. return -1
  1271. }
  1272. w: int
  1273. if str[0] == quote && quote == '"' {
  1274. return
  1275. } else if str[0] >= 0x80 {
  1276. r, w = utf8.decode_rune_in_string(str)
  1277. return r, true, str[w:], true
  1278. } else if str[0] != '\\' {
  1279. return rune(str[0]), false, str[1:], true
  1280. }
  1281. if len(str) <= 1 {
  1282. return
  1283. }
  1284. s := str
  1285. c := s[1]
  1286. s = s[2:]
  1287. switch c {
  1288. case:
  1289. return
  1290. case 'a': r = '\a'
  1291. case 'b': r = '\b'
  1292. case 'f': r = '\f'
  1293. case 'n': r = '\n'
  1294. case 'r': r = '\r'
  1295. case 't': r = '\t'
  1296. case 'v': r = '\v'
  1297. case '\\': r = '\\'
  1298. case '"': r = '"'
  1299. case '\'': r = '\''
  1300. case '0'..='7':
  1301. v := int(c-'0')
  1302. if len(s) < 2 {
  1303. return
  1304. }
  1305. for i in 0..<len(s) {
  1306. d := int(s[i]-'0')
  1307. if d < 0 || d > 7 {
  1308. return
  1309. }
  1310. v = (v<<3) | d
  1311. }
  1312. s = s[2:]
  1313. if v > 0xff {
  1314. return
  1315. }
  1316. r = rune(v)
  1317. case 'x', 'u', 'U':
  1318. count: int
  1319. switch c {
  1320. case 'x': count = 2
  1321. case 'u': count = 4
  1322. case 'U': count = 8
  1323. }
  1324. if len(s) < count {
  1325. return
  1326. }
  1327. for i in 0..<count {
  1328. d := hex_to_int(s[i])
  1329. if d < 0 {
  1330. return
  1331. }
  1332. r = (r<<4) | rune(d)
  1333. }
  1334. s = s[count:]
  1335. if c == 'x' {
  1336. break
  1337. }
  1338. if r > utf8.MAX_RUNE {
  1339. return
  1340. }
  1341. multiple_bytes = true
  1342. }
  1343. success = true
  1344. tail_string = s
  1345. return
  1346. }
  1347. /*
  1348. Unquotes the input string considering any type of quote character and returns the unquoted string
  1349. **Inputs**
  1350. - lit: The input string to unquote
  1351. - allocator: (default: context.allocator)
  1352. WARNING: This procedure gives unexpected results if the quotes are not the first and last characters.
  1353. Example:
  1354. import "core:fmt"
  1355. import "core:strconv"
  1356. unquote_string_example :: proc() {
  1357. src:="\"The raven Huginn is black.\""
  1358. s, allocated, ok := strconv.unquote_string(src)
  1359. fmt.println(src)
  1360. fmt.printf("Unquoted: <%s>, alloc:%v, ok:%v\n\n", s, allocated, ok)
  1361. src="\'The raven Huginn\' is black."
  1362. s, allocated, ok = strconv.unquote_string(src)
  1363. fmt.println(src)
  1364. fmt.printf("Unquoted: <%s>, alloc:%v, ok:%v\n\n", s, allocated, ok)
  1365. src="The raven \'Huginn\' is black."
  1366. s, allocated, ok = strconv.unquote_string(src) // Will produce undesireable results
  1367. fmt.println(src)
  1368. fmt.printf("Unquoted: <%s>, alloc:%v, ok:%v\n", s, allocated, ok)
  1369. }
  1370. Output:
  1371. "The raven Huginn is black."
  1372. Unquoted: <The raven Huginn is black.>, alloc:false, ok:true
  1373. 'The raven Huginn' is black.
  1374. Unquoted: <The raven Huginn' is black>, alloc:false, ok:true
  1375. The raven 'Huginn' is black.
  1376. Unquoted: <he raven 'Huginn' is black>, alloc:false, ok:true
  1377. **Returns**
  1378. - res: The resulting unquoted string
  1379. - allocated: A boolean indicating if the resulting string was allocated using the provided allocator
  1380. - success: A boolean indicating whether the unquoting was successful
  1381. NOTE: If unquoting is unsuccessful, the allocated memory for the result will be freed.
  1382. */
  1383. unquote_string :: proc(lit: string, allocator := context.allocator) -> (res: string, allocated, success: bool) {
  1384. contains_rune :: proc(s: string, r: rune) -> int {
  1385. for c, offset in s {
  1386. if c == r {
  1387. return offset
  1388. }
  1389. }
  1390. return -1
  1391. }
  1392. if len(lit) < 2 {
  1393. return
  1394. }
  1395. if lit[0] == '`' {
  1396. return lit[1:len(lit)-1], false, true
  1397. }
  1398. s := lit
  1399. quote := '"'
  1400. if s == `""` {
  1401. return "", false, true
  1402. }
  1403. s = s[1:len(s)-1]
  1404. if contains_rune(s, '\n') >= 0 {
  1405. return s, false, false
  1406. }
  1407. if contains_rune(s, '\\') < 0 && contains_rune(s, quote) < 0 {
  1408. if quote == '"' {
  1409. return s, false, true
  1410. }
  1411. }
  1412. context.allocator = allocator
  1413. buf_len := 3*len(s) / 2
  1414. buf := make([]byte, buf_len)
  1415. offset := 0
  1416. for len(s) > 0 {
  1417. r, multiple_bytes, tail_string, ok := unquote_char(s, byte(quote))
  1418. if !ok {
  1419. delete(buf)
  1420. return s, false, false
  1421. }
  1422. s = tail_string
  1423. if r < 0x80 || !multiple_bytes {
  1424. buf[offset] = byte(r)
  1425. offset += 1
  1426. } else {
  1427. b, w := utf8.encode_rune(r)
  1428. copy(buf[offset:], b[:w])
  1429. offset += w
  1430. }
  1431. }
  1432. new_string := string(buf[:offset])
  1433. return new_string, true, true
  1434. }