代码之家  ›  专栏  ›  技术社区  ›  user310291

将Rebol csv工具转换为红色

  •  2
  • user310291  · 技术社区  · 7 年前

    我开始皈依 http://www.rebol.org/view-script.r?script=csv-tools.r 从Rebol到Red;我被困在二进制的“字符串”上,在Rebol上找不到关于它们的文档。

        to-iso-date: func [
          "Convert a date to ISO format (Excel-compatible subset)"
          date [date!] /utc "Convert zoned time to UTC time"
        ] [
          if utc [date: date + date/zone date/zone: none] ; Excel doesn't support the Z suffix
          either date/time [ajoin [
            next form 10000 + date/year "-"
            next form 100 + date/month "-"
            next form 100 + date/day " "  ; ... or T
            next form 100 + date/time/hour ":"
            next form 100 + date/time/minute ":"
            next form 100 + date/time/second  ; ... or offsets
          ]] [ajoin [
            next form 10000 + date/year "-"
            next form 100 + date/month "-"
            next form 100 + date/day
          ]]
        ]
    
        to-csv: func [
          "Convert a block of values to a CSV-formatted line in a string."
          [catch]
          data [block!] "Block of values"
          delimiter [char! string! binary!] {Default ","}
          ; Empty delimiter, " or CR or LF may lead to corrupt data
        ][
          output: make block! 2 * length? data
          delimiter: either with [to-string delimiter] [","]
          unless empty? data [insert tail output format-field first data data: next data]
          foreach x data [insert insert tail output delimiter format-field get/any 'x]
          to-string output
    
          format-field: func [x [any-type!]] [case [
            any [not value? 'x error? get/any 'x] [throw-error 'script 'expect-set [
              [any-string! any-word! any-path! binary! scalar! date!] type? get/any 'x
            ]]
            none? :x [""]
            any-string? :x [ajoin [{"} replace/all copy x {"} {""} {"}]]
            :x == #"^(22)" [{""""}]  ; Weirdly, = and =? return true when x is 34
            char? :x [ajoin [{"} x {"}]]
            money? :x [find/tail form x "$"]
            scalar? :x [form x]
            date? :x [to-iso-date x]
            any [any-word? :x binary? :x any-path? :x] [
              ajoin [{"} replace/all to-string :x {"} {""} {"}]
            ]
            'else [throw-error 'script 'expect-set reduce [
              [any-string! any-word! any-path! binary! scalar! date!] type? :x
            ]]
          ]]
        ]
    
        load-csv: func [
          "Load and parse CSV-style delimited data. Returns a block of blocks."
          [catch]
          source [file! url! string! binary! block!] "File or url will be read"
          /binary "Don't convert the data to string (if it isn't already)"
          delimiter [char! string! binary!] {Default #","}
          /into "Insert into a given block, rather than make a new one"
          output [block!] "Block returned at position after the insert"
          /part "Get only part of the data, and set to the position afterwards"
          count [integer!] "Number of lines to return"
          after [any-word! none!] "Set to data at position after decoded part"
        ] [
          if block? source [ ; Many sources, load them all into the same output block
            unless into [output: make block! length? source]
            unless with [delimiter: ","]
            x: [file! url! string! binary!]
            foreach y source [
              unless find x type?/word y [
                cause-error 'script 'expect-set reduce [x type? :y]
              ]
              either binary [
                output: load-csv/binary/with/into y delimiter output
              ] [
                output: load-csv/with/into y delimiter output
              ]
            ]
            return either into [output] [head output]
          ]
          ; Read the source if necessary
          if any [file? source url? source] [throw-on-error [
            source: either binary [read/binary source] [read source]
          ]]
          unless binary [source: as-string source] ; No line conversion
          ; Use either a string or binary value emitter
          emit: either binary? source [:as-binary] [:as-string]
          ; Prep output and local vars
          unless into [output: make block! 1]
          line: [] val: make string! 0
          ; Parse rules
          valchars: remove/part charset [#"^(00)" - #"^(FF)"] crlf
          case [
            any [char? delimiter: any [delimiter ","] last? delimiter] [ ; One char
              valchars: compose [any (remove/part valchars delimiter)]
            ]
            empty? delimiter [throw-error 'script 'invalid-arg delimiter]
            'else [ ; Multi-character delimiter needs special handling
              remove/part valchars copy/part as-string delimiter 1
              valchars: compose/deep [any [
                some (valchars) | y: delimiter :y break | (first as-string delimiter)
              ]]
            ]
          ]
          value: [
            ; Value in quotes, with Excel-compatible handling of bad syntax
            {"} (clear val) x: [to {"} | to end] y: (insert/part tail val x y)
            any [{"} x: {"} [to {"} | to end] y: (insert/part tail val x y)]
            [{"} x: valchars y: (insert/part tail val x y) | end]
            (insert tail line emit copy val) |
            ; Raw value
            x: valchars y: (insert tail line emit copy/part x y)
          ]
          part: pick [ ; Rule must fail and go to the alternate in order to continue
            [end skip]  ; Will always fail, so the break won't be reached
            [(cont: if positive? count [count: count - 1 [end skip]]) cont]
            ; While count is positive, cont is set to [end skip], which will fail
            ; and go the alternate. Otherwise, cont is set to none, which will
            ; succeed, and then the subsequent break will stop the parsing.
            ; Parsing control flow can get a little convoluted at times in R2.
          ] not part
          ; as-string because R2 doesn't parse binary that well
          parse/all as-string source [z: any [
            end break | part break |
            (line: make block! length? line)
            value any [delimiter value] [crlf | cr | lf | end]
            (output: insert/only output line)
          ] z:]
          if after [set after either binary? source [as-binary z] [z]]
          also either into [output] [head output]
            (source: output: line: val: x: y: none) ; Free the locals
        ]
    
    1 回复  |  直到 7 年前
        1
  •  2
  •   rebolek    7 年前

    as-string as-binary Rebol3是以不同格式表示数据的特定函数,即。 binary! 数据为UTF-8字符串。以红色显示,按所需格式加载数据 read 对于字符串和 read/binary 对于二进制数据。

    你也可以看看 https://github.com/rebolek/red-tools/blob/master/csv.red 用于简单的CSV编码器/解码器。