2012-11-19 33 views
5

मैं एक CSV लाइन को रीबोल ब्लॉक में बदलने के लिए PARSE का उपयोग करने का प्रयास कर रहा हूं। खुले कोड में लिखने में काफी आसान है, लेकिन अन्य प्रश्नों के साथ मैं सीखने की कोशिश कर रहा हूं कि बोली इसके बिना क्या कर सकती है।सीएसवी से लाइन में पढ़ने के लिए PARSE बोली का उपयोग कैसे करें?

तो एक लाइन का कहना है यदि: सूचना के लिए

[{Look, that's "MR. Fork" to you!} {Hostile Fork} none {http://hostilefork.com}] 

मुद्दे::

"Look, that's ""MR. Fork"" to you!",Hostile Fork,,http://hostilefork.com 

तब मैं ब्लॉक चाहते

  • सीएसवी तार में एंबेडेड उद्धरण ""
  • साथ दिखाई देते हैं
  • कॉमा उद्धरण और एच के अंदर हो सकता है शाब्दिक, नहीं एक स्तंभ विभाजक के खिलाडि़यों हिस्सा
  • सटे स्तंभ को अलग करने के लिए अल्पविराम एक खाली क्षेत्र से संकेत मिलता है
  • स्ट्रिंग्स कि उद्धरण शामिल नहीं है या अल्पविराम उद्धरण
  • पल हम चीजों को रख सकते हैं के लिए बिना प्रदर्शित हो सकता STRING के रूप में http://rebol.com की तरह! LOAD के बजाय इस तरह के URL!

यह अधिक समान बनाने के रूप में प्रकार में उन्हें ing, पहली बात मैं कर इनपुट लाइन के लिए एक अल्पविराम संलग्न है। तब मेरे पास column-rule है जो एक अल्पविराम द्वारा समाप्त एक कॉलम को कैप्चर करता है ... जो या तो उद्धरण में हो सकता है या नहीं।

मुझे पता है कि कितने कॉलम वहाँ हैडर लाइन की वजह से होना चाहिए, इसलिए कोड तो कहते हैं:

unless parse line compose [(column-count) column-rule] [ 
    print rejoin [{Expected } column-count { columns.}] 
] 

लेकिन मैं थोड़ा column-rule लेखन पर अटक कर रहा हूँ। मुझे व्यक्त करने के लिए बोली में एक तरीका चाहिए "एक बार जब आप उद्धरण प्राप्त कर लेते हैं, तब तक उद्धरण जोड़ों को छोड़ दें जब तक कि आप अपने आप को एक उद्धरण खड़े न हों।" ऐसा करने का एक अच्छा तरीका क्या है?

उत्तर

3

अधिकांश पार्स समस्याओं के साथ, मैं एक व्याकरण बनाने की कोशिश करता हूं जो इनपुट प्रारूप के तत्वों का सबसे अच्छा वर्णन करता है।

[comma ending value-chars qmark quoted-chars value header row] 

कुछ क्रियाएं:

[row-feed emit-value] 

और ऑपरेटिव संज्ञाओं:

[current chunk current-row width] 

मुझे लगता है मैं संभवतः यह टूट सकता नीचे एक

इस मामले में, हम संज्ञाओं है थोड़ा और, लेकिन साथ काम करने के लिए पर्याप्त है। सबसे पहले, नींव:

comma: "," 
ending: "^/" 
qmark: {"} 
value-chars: complement charset reduce [qmark comma ending] 
quoted-chars: complement charset reduce [qmark] 

अब मूल्य संरचना। के रूप में हम उन्हें खोजने उद्धरित मान मान्य वर्ण या उद्धरण का हिस्सा से बने होते हैं:

current: chunk: none 
quoted-value: [ 
    qmark (current: copy "") 
    any [ 
     copy chunk some quoted-chars (append current chunk) 
     | 
     qmark qmark (append current qmark) 
    ] 
    qmark 
] 

value: [ 
    copy current some value-chars 
    | quoted-value 
] 

emit-value: [ 
    (
     delimiter: comma 
     append current-row current 
    ) 
] 

emit-none: [ 
    (
     delimiter: comma 
     append current-row none 
    ) 
] 

ध्यान दें कि delimiter प्रत्येक पंक्ति की शुरुआत में ending के लिए सेट है, तो comma को जैसे ही हम एक मूल्य के पारित बदल दिया है।इस प्रकार, एक इनपुट पंक्ति को [ending value any [comma value]] के रूप में परिभाषित किया जाता है।

सभी कि रहता दस्तावेज़ संरचना को परिभाषित करने के लिए है:

current-row: none 
row-feed: [ 
    (
     delimiter: ending 
     append/only out current-row: copy [] 
    ) 
] 

width: none 
header: [ 
    (out: copy []) 
    row-feed any [ 
     value comma 
     emit-value 
    ] 
    value body: ending :body 
    emit-value 
    (width: length? current-row) 
] 

row: [ 
    row-feed width [ 
     delimiter [ 
      value emit-value 
      | emit-none 
     ] 
    ] 
] 

if parse/all stream [header some row opt ending][out] 

यह लपेटें अप उन सभी शब्दों को बचाने के लिए, और तुम हो:

REBOL [ 
    Title: "CSV Parser" 
    Date: 19-Nov-2012 
    Author: "Christopher Ross-Gill" 
] 

parse-csv: use [ 
    comma ending delimiter value-chars qmark quoted-chars 
    value quoted-value header row 
    row-feed emit-value emit-none 
    out current current-row width 
][ 
    comma: "," 
    ending: "^/" 
    qmark: {"} 
    value-chars: complement charset reduce [qmark comma ending] 
    quoted-chars: complement charset reduce [qmark] 

    current: none 
    quoted-value: use [chunk][ 
     [ 
      qmark (current: copy "") 
      any [ 
       copy chunk some quoted-chars (append current chunk) 
       | 
       qmark qmark (append current qmark) 
      ] 
      qmark 
     ] 
    ] 

    value: [ 
     copy current some value-chars 
     | quoted-value 
    ] 

    current-row: none 
    row-feed: [ 
     (
      delimiter: ending 
      append/only out current-row: copy [] 
     ) 
    ] 
    emit-value: [ 
     (
      delimiter: comma 
      append current-row current 
     ) 
    ] 
    emit-none: [ 
     (
      delimiter: comma 
      append current-row none 
     ) 
    ] 

    width: none 
    header: [ 
     (out: copy []) 
     row-feed any [ 
      value comma 
      emit-value 
     ] 
     value body: ending :body 
     emit-value 
     (width: length? current-row) 
    ] 

    row: [ 
     opt ending end break 
     | 
     row-feed width [ 
      delimiter [ 
       value emit-value 
       | emit-none 
      ] 
     ] 
    ] 

    func [stream [string!]][ 
     if parse/all stream [header some row][out] 
    ] 
] 
+0

मेरे द्वारा दिए गए निराला डेटा पर काम करने के लिए (अब तक) एक उत्तर पर शानदार प्रतिक्रिया समय लगता है! – HostileFork

2

मैं साल पहले कि करना था। मैंने अपने funcs को उन सभी मामलों को संभालने के लिए अपडेट किया है जिन्हें मैंने पाया था। मुझे आशा है कि यह अब और अधिक ठोस है।

सूचना है कि यह लेकिन अंदर नई-पंक्तियों के साथ तार संभाल कर सकते हैं:

तार में
  1. नई पंक्तियां केवल और वामो किया जाना चाहिए ... रिकॉर्ड के बीच
  2. न्यू लाइन CRLF और होना चाहिए ..
  3. आपको फ़ाइल को पढ़ने/बाइनरी के साथ लोड करना होगा ताकि Rebol newlines automaticaly को परिवर्तित न करे।

; Conversion function from CSV format 
csv-to-block: func [ 
    "Convert a string of CSV formated data to a Rebol block. First line is header." 
    csv-data [string!] "CSV data." 
    /separator separ [char!] "Separator to use if different of comma (,)." 
    /without-header "Do not include header in the result." 
    /local out line start end this-string header record value data chars spaces chars-but-space 
    ; CSV format information http://www.creativyst.com/Doc/Articles/CSV/CSV01.htm 
] [ 
    out: copy [] 
    separ: any [separ #","] 

    ; This function handle replacement of dual double-quote by quote while copying substring 
    this-string: func [s e] [replace/all copy/part s e {""} {"}] 
    ; CSV parsing rules 
    header: [(line: copy []) value any [separ value | separ (append line none)] (if not without-header [append/only out line])] 
    record: [(line: copy []) value any [separ value | separ (append line none)] (append/only out line)] 
    value: [any spaces data any spaces (append line this-string start end)] 
    data: [start: some chars-but-space any [some spaces some chars-but-space] end: | #"^"" start: any [some chars | {""} | separ | newline] end: #"^""] 
    chars: complement charset rejoin [ {"} separ newline] 
    spaces: charset exclude { ^-} form separ 
    chars-but-space: exclude chars spaces 

    parse/all csv-data [header any [newline record] any newline end] 
    out 
] 

यदि आवश्यक हो, मैं समकक्ष block-to-csv है (1. और 2. क्या एक्सेल उदाहरण के लिए देते हैं, है)।

[संपादित करें] ठीक है, समकक्ष (ध्यान दें: सभी स्ट्रिंग दोहरे उद्धरण और हेडर के साथ संलग्न किया जाएगा ब्लॉक की पहली पंक्ति में होना चाहिए अगर आप इसे परिणाम में चाहते हैं):

block-to-csv: func [ 
    "Convert a block of blocks to a CSV formated string." 
    blk-data [block!] "block of data to convert" 
    /separator separ "Separator to use if different of comma (,)." 
    /local out csv-string record value v 
] [ 
    out: copy "" 
    separ: any [separ #","] 
    ; This function convert a string to a CSV formated one 
    csv-string: func [val] [head insert next copy {""} replace/all replace/all copy val {"} {""} newline #{0A} ] 
    record: [into [some [value (append out separ)]]] 
    value: [set v string! (append out csv-string v) | set v any-type! (append out form v)] 

    parse/all blk-data [any [record (remove back tail out append out crlf)]] 
    out 
] 
+0

अरे, धन्यवाद! मुझे वास्तव में इस कार्य के लिए 'ब्लॉक-टू-सीएसवी' की आवश्यकता है, इसलिए यदि आप इसे फेंकने के उत्तर को संपादित करना चाहते हैं, तो यह मुझे इसे लिखने से रोक देगा (भले ही यह दोनों के लिए आसान हो)। – HostileFork

2

इसके अतिरिक्त, ब्रायनएच से rebol.org पर% csv-tools.r स्क्रिप्ट पाएं।

http://www.rebol.org/view-script.r?script=csv-tools.r

कोड के महान टुकड़ा। आर 2 और आर 3 के साथ काम करता है।