Login
7 branches 0 tags
Ben (X13/Void) Fixed bugs and added a `wc` test 89eb248 3 years ago 431 Commits
nujel / stdlib / string / string.nuj
; Nujel - Copyright (C) 2020-2021 - Benjamin Vincent Schulenburg
; This project uses the MIT license, a copy should be included under /LICENSE

;; Some nujel string λs

[defun println [str]
       "Print STR on a single line"
       [print [cat str "\r\n"]]]

[defun errorln [str]
       "Print to stderr STR on a single line"
       [print [cat str "\r\n"]]]

[defun display [value]
        "Display VALUE"
        [print value]]

[defun newline []
        "Print a single line feed character"
        [display "\r\n"]]

[defun br [num]
       "Return NUM=1 linebreaks"
       [if [or [nil? num] [<= [int num] 1]]
           "\n"
           [cat "\n" [br [+ -1 num]]]]]

[defun path/ext?! [ext]
       "Return a predicate that checks if a path ends on EXT"
       [λ [path]
          [== ext [lowercase [path/extension path]]]]]

[defun path/extension [path]
       "Return the extension of PATH"
       [def last-period [last-index-of path "."]]
       [if [>= last-period 0]
           [string/cut path [+ 1 last-period] [string/length path]]
           path]]

[defun path/without-extension [path]
       "Return PATH, but without the extension part"
       [def last-period [last-index-of path "."]]
       [if [>= last-period 0]
           [string/cut path 0 last-period]
           path]]

[defun int->string/binary [α]
       "Turn α into a its **binary** string representation"
       [def ret ""]
       [when-not α [def α 0]]
       [when [zero? α] [set! ret "0"]]
       [while [not-zero? α]
              [set! ret [cat [from-char-code [+ #\0 [logand α #b1]]] ret]]
              [set! α [ash α -1]]]
       ret]

[defun int->string/octal [α]
       "Turn α into a its **octal** string representation"
       [def ret ""]
       [when-not α [def α 0]]
       [when [zero? α] [set! ret "0"]]
       [while [not-zero? α]
              [set! ret [cat [from-char-code [+ #\0 [logand α #b111]]] ret]]
              [set! α [ash α -3]]]
       ret]

[def int->string/HEX [let*
     "Turn α into a its **hexadecimal** string representation"
     [def conversion-arr #["0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "A" "B" "C" "D" "E" "F"]]

     [λ [α]
         [def ret ""]
         [when-not α [def α 0]]
         [when [zero? α] [set! ret "0"]]
         [while [not-zero? α]
                [set! ret [cat [array/ref conversion-arr [logand α #b1111]] ret]]
                [set! α [ash α -4]]]
         ret]]]

[defun int->string/hex [α]
       "Turn α into a its **hexadecimal** string representation"
       [lowercase [int->string/HEX α]]]

[defun int->string/decimal [α]
        "Turn α into a its **decimal** string representation"
        [string α]]
[def int->string int->string/decimal]

[defun string/pad-start [text goal-length char]
       "Pad out TEXT with CHAR at the start until it is GOAL-LENGTH chars long, may also truncate the string"
       [when-not char [set! char " "]]
       [when-not [string? text] [set! text [string text]]]
       [when-not [string? char]
                 [throw [list :type-error "string/pad-start needs char as a string, so that one can pad with multiple characters" char [current-lambda]]]]
       [while [< [string/length text] goal-length]
              [set! text [cat char text]]]
       [if [> [string/length text] goal-length]
           [string/cut text [- [string/length text] goal-length] [string/length text]]
           text]]

[defun string/pad-end [text goal-length char]
       "Pad out TEXT with CHAR at the end until it is GOAL-LENGTH chars long, may also truncate the string"
       [when-not char [set! char " "]]
       [when-not [string? text] [set! text [string text]]]
       [when-not [string? char]
                 [throw [list :type-error "string/pad-start needs char as a string, so that one can pad with multiple characters" char [current-lambda]]]]
       [while [< [string/length text] goal-length]
              [set! text [cat text char]]]
       [if [> [string/length text] goal-length]
           [string/cut text 0 goal-length]
           text]]

[defun string/pad-middle [text goal-length char]
       "Pad out TEXT with CHAR at the end until it is GOAL-LENGTH chars long, may also truncate the string"
       [when-not char [set! char " "]]
       [when-not [string? text] [set! text [string text]]]
       [when-not [string? char]
                 [throw [list :type-error "string/pad-middle needs char as a string, so that one can pad with multiple characters" char [current-lambda]]]]
       [while [< [string/length text] goal-length]
              [set! text [cat char text char]]]
       [if [> [string/length text] goal-length]
           [let [[end-overflow [/ [- [string/length text] goal-length] 2]]
                 [start-overflow [- [- [string/length text] goal-length] end-overflow]]]
                [string/cut text start-overflow [+ start-overflow goal-length]]]
           text]]

[defun string/round [text decimal-digits]
       "Round the floating point representation in TEXT to have at most DECIMAL-DIGITS after the period"
       [def pos [last-index-of text "."]]
       [if [>= pos 0]
           [string/cut text 0 [+ pos 1 decimal-digits]]
           text]]

[defun split/empty [str separator]
       [def slen [string/length str]]
       [def start 0]
       [def ret #nil]
       [while [< start slen]
	      [set! ret [cons [string/cut str start [+ 1 start]] ret]]
	      [++ start]]
       [reverse ret]]

[defun split/string [str separator start]
       [when-not start [set! start 0]]
       [def pos-found [index-of str separator start]]
       [if [>= pos-found 0]
	   [cons [string/cut str start pos-found]
		 [split/string str separator [+ pos-found [string/length separator]]]]
	   [cons [string/cut str start [string/length str]]
		 #nil]]]

[defun split [str separator]
       [case [string/length separator]
             [[0] [split/empty str]]
             [otherwise [split/string str separator 0]]]]

[defun read/single [text]
       [car [read text]]]

[defun string/length?! [chars]
       [λ [a] [== chars [string/length a]]]]

[defun contains-any? [str chars]
       [apply or [map [split chars ""] [λ [a] [>= [index-of str a] 0]]]]]

[defun contains-all? [str chars]
       [apply and [map [split chars ""] [λ [a] [>= [index-of str a] 0]]]]]