parse-int-values: func [ "Parses and returns integer values, each <n> chars long in a string." input [any-string!] spec [block!] "Dialected block of commands: <n>, skip <n>, done, char, or string" /local gen'd-rules ; generated rules result ; what we return to the caller emit emit-data-rule emit-skip-rule emit-literal-rule emit-data digit= n= literal= int-rule= skip-rule= literal-rule= done= build-rule= data-rule skip-rule ][ ; This is where we put the rules we build; our gernated parse rules. gen'd-rules: copy [] ; This is where we put the integer results result: copy [] ; helper functions emit: func [rule n] [append gen'd-rules replace copy rule 'n n] emit-data-rule: func [n] [emit data-rule n] emit-skip-rule: func [n] [emit skip-rule n] emit-literal-rule: func [value] [append gen'd-rules value] emit-data: does [append result to integer! =chars] ; Rule templates; used to generate rules ;data-rule: [copy =chars n digit= (append result to integer! =chars)] data-rule: [copy =chars n digit= (emit-data)] skip-rule: [n skip] ; helper parse rules digit=: charset [#"0" - #"9"] n=: [set n integer!] literal=: [set lit-val [char! | any-string!]] ; Rule generation helper parse rules int-rule=: [n= (emit-data-rule n)] skip-rule=: ['skip n= (emit-skip-rule n)] literal-rule=: [literal= (emit-literal-rule lit-val)] done=: ['done (append gen'd-rules [to end])] ; This generates the parse rules used against the input build-rule=: [some [skip-rule= | int-rule= | literal-rule=] opt done=] ; We parse the spec they give us, and use that to generate the ; parse rules used against the actual input. If the spec parse ; fails, we return none (maybe we should throw an error though); ; if the data parse fails, we return false; otherwise they get ; back a block of integers. Have to decide what to do if they ; give us negative numbers as well. either parse spec build-rule= [ either parse input gen'd-rules [result] [false] ] [none] ] comment { test: func [val spec] [print mold parse-int-values val spec] test "20060228T190000" [4 2 2 skip 1 2 2 2] test "20060228T190000" [4 2 2 #"T" 2 2 2] test "20060228T190000Z" [4 2 2 #"T" 2 2 2 #"Z"] test "20060228T190000Z" [4 2 2 #"T" 2 2 2 done] test %2006021509450004.jpg [4 2 2 2 2 4 skip 4] test %2006021509450004.jpg [4 2 2 2 2 4 done] ; tests that *should* fail ; Bad spec test "20060228T190000Z" [4 2 x #"T" 2 2 2] test "20060228T190000Z" [4 2 2 #"T" 2.5 2 2] ; Bad input test "20060228T190000Z" [4 2 2 #"T" 2 2 2] test "2000228T190000Z" [4 2 2 #"T" 2 2 2 done] test "20060228x190000Z" [4 2 2 #"T" 2 2 2 done] }
You need to create an account or log in to post comments to this site.