DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world
STEP - Alpha-numeric String Incrementer
step: func [ ; INCR SUCC ADVANCE NEXT-STR, inspired by Ruby's succ method.
"Increments strings, skipping non-alpha-num chars; doesn't auto-grow if first char is not alpha-num."
series [string!]
/local digit= alpha= alpha-num= =val carry? step-val mark
range-start-char range-start-char? grow-if-necessary
][
if empty? series [return series]
digit=: charset [#"0" - #"9"]
alpha=: charset [#"A" - #"Z" #"a" - #"z"]
alpha-num=: union alpha= digit=
carry?: does [find "9Zz" =val]
range-start-char?: func [val] [find "0Aa" val]
; This gives us the new "rollover digit" to add, when we need
; to grow a string. Zeros rolling to ones is the exception to
; the rule; otherwise, we just add the same char that's there
; (the starting char for a range).
;
range-start-char: func [val] [
select/case [#"0" #"1" #"A" #"A" #"a" #"a"] val
]
grow-if-necessary: does [
if range-start-char? last series [
append series range-start-char last series
]
]
; Increment a char val, rolling over if necessary.
step-val: func [val] [
either find "9Zz" val [
select/case [#"9" #"0" #"Z" #"A" #"z" #"a"] val
] [add val 1]
]
catch [
; Reverse the series, so we can parse left to right.
parse/case reverse series [
some [
mark:
copy =val alpha-num= (
change mark step-val to char! =val
; Carry? means the char we just found will cause
; a "carry" to the next digit, so we keep going;
; otherwise, we're done
if not carry? [throw]
)
; We just skip over non-alph-num chars in the current
; design.
| skip
]
]
; If we stopped carrying at some point, we won't get here.
grow-if-necessary
]
; We reversed the series to parse it, so reverse it again.
reverse series
]
; test-step: func [val expected-result] [
; if expected-result <> step copy val [
; print ["Test Failed:" mold val mold step copy val]
; ]
; ]
; foreach [val res] [
; "" ""
; "!" "!"
; "!@#$%^&*()" "!@#$%^&*()"
; "aa" "ab"
; "aaa" "aab"
; "az" "ba"
; "aZ" "bA"
; "zz" "aaa"
; "#zz" "#aa"
; "ZZ" "AAA"
; "!ZZ" "!AA"
; "001" "002"
; "009" "010"
; "099" "100"
; "999" "1000"
; "~999" "~000"
; "123@999" "124@000"
; "1.2.3" "1.2.4"
; "001#1.2.9" "001#1.3.0"
; "001#9.9.9" "002#0.0.0"
; "001-zzz" "002-aaa"
; ] [test-step val res]





