2017-05-16 56 views
1

我golang CSV處理程序副本:Golang:在處理CSV時,重新格式化單行?幾乎完全從<a href="https://golang.org/pkg/encoding/csv/" rel="nofollow noreferrer">Package CSV</a>例如

func processCSV(path string){ 

    file:= utils.OpenFile(path) 
    reader:= csv.NewReader(file) 
    reader.LazyQuotes = true 

    cs:= []*Collision{} //defined elsewhere 

    for { 

     line, err := reader.Read() 

     //Kill processing if we're at EOF 
     if err == io.EOF { 
      break 
     } 

     c := get(line) //defined elsewhere 
     cs= append(cs, c) 
    } 

    //Do other stuff... 
} 

代碼的偉大工程,直到它遇到CSV的格式不正確的線,一般看起來是這樣的(?):

物品1 ,item2,「item3」,有奇怪的引用「」,「item4」,item5

csvReader.LazyQuotes = true選項似乎沒有提供足夠的寬容來閱讀這一行,因爲我需要它。

我的問題是這樣的:我可以問問csv讀者的原始線,以便我可以「按摩」它來提取我需要的東西嗎?我正在使用的文件大小適中(〜150mb),我不確定我想重新執行它們,特別是每個文件只有幾行有這樣的問題。

感謝您的任何提示!

回答

0

據我所知encoding/csv沒有提供任何這樣的功能,所以你可以尋找一些第三方的csv包,或者你可以自己實現一個解決方案。

如果你想去DIY路線,我可以給你一個提示,不管這是一個很好的提示,你應該實施取決於你。

您可以實現一個io.Reader封裝您的文件並跟蹤最後一行讀取,然後每次因錯誤的csv導致錯誤時您可以使用您的閱讀器重讀該行,按摩它,將其添加到結果中,並讓循環繼續,就好像什麼都沒有發生。

這裏有一個如何你processCSV會改變一個例子:

func processCSV(path string){ 

    file := utils.OpenFile(path) 
    myreader := NewMyReader(file) 
    reader := csv.NewReader(myreader) 
    reader.LazyQuotes = true 

    cs:= []*Collision{} //defined elsewhere 

    for { 

     line, err := reader.Read() 

     //Kill processing if we're at EOF 
     if err == io.EOF { 
      break 
     } 

     // malformed csv 
     if err != nil { 
      // Just reread the last line and on the next iteration of 
      // the loop myreader.Read should continue returning bytes 
      // that come after this malformed line to the csv.Reader. 
      l, err := myreader.CurrentLine() 
      if err != nil { 
       panic(err) 
      } 

      // massage the malformed csv line 
      line = fixcsv(l) 
     } 

     c := get(line) //defined elsewhere 
     cs= append(cs, c) 
    } 

    //Do other stuff... 
} 
0

看着csv.Read()的實現,你不能用csv包來做你正在尋找的東西。它使用模塊 - 專用功能parseRecord(),它很努力。

我想你需要的是編寫自己的CSV閱讀器將處理該案件或者乾脆進行預處理由線文件中的行,這樣畸形的項目將是例如從"更換,\"(其中csv包可以正確處理)。

0

我使用從Go的CSV解析代碼mkopriva和公然複製一個暗示「解決」這個問題。如果我讀得對,Go的CSV解析器對於它認爲的一行很聰明。當我編寫了一個樸素的CSV解析器時,我已經將文件拆分爲新行,然後對其進行處理。 Go的解析器更聰明,並且包含引用字段本身可能包含新行的可能性。在這些情況下,我的代碼會失敗,他們的工作將會發揮作用。

爲Go的解析器提供「線條」有點棘手,因爲它正在通過流讀取線路開始和結束模式並提取字段。我所做的就是劫持代碼並添加一個跟蹤代碼視爲流的開始和結束的變量。我的補充可能有問題,但似乎爲我工作。如果有幫助,下面是我採取的步驟:

1)將CSV source複製並粘貼到我的項目中。

2)添加新的字段中鍵入閱讀器結構{}:

type Reader struct { 
    ... 
    // The i'th field starts at offset fieldIndexes[i] in lineBuffer. 
    fieldIndexes []int 

    CurrentLine []byte //Added struct field to hold onto the line 

    ... 
} 

3)在readRune(),捕獲字節,因爲他們進來,像這樣:

func (r *Reader) readRune() (rune, error) { 
    r1, _, err := r.r.ReadRune() 
    r.CurrentLine = append(r.CurrentLine, byte(r1)) //added: stores bytes as processed 
    ... 
} 

4)在閱讀(),復位CurrentLine的每一行,像這樣:

func (r *Reader) Read() (record []string, err error) { 

    r.CurrentLine = []byte{} //added: reset line capturing 

    ... 
} 

隨着這些項目加入,然後我就可以抓取當前行的時候有一個解析錯誤,因爲每mkopriva的建議:

... 
if err != nil { 

    line = fixCSV(csvReader.CurrentLine) 
    continue 

} 
... 
相關問題