正在分析CSV文件,该文件包含一个标题块";评论“;

正在分析CSV文件,该文件包含一个标题块";评论“;,csv,parsing,go,text,Csv,Parsing,Go,Text,我正试图解析一个托管在远程位置的CSV文件,但令人烦恼的是,该文件顶部包含一些自述注释,格式如下: ###### # some readme text, # some more, comments ###### 01-02-03,123,foo,http://example.com 04-05-06,789,baz,http://another.com 我试图使用以下代码来提取数据中的URL,但由于顶部的注释,它抛出了一个错误,称字段数错误,可能是试图将它们解析为CSV内容 type my

我正试图解析一个托管在远程位置的CSV文件,但令人烦恼的是,该文件顶部包含一些自述注释,格式如下:

######
# some readme text,
# some more, comments
###### 
01-02-03,123,foo,http://example.com 
04-05-06,789,baz,http://another.com
我试图使用以下代码来提取数据中的URL,但由于顶部的注释,它抛出了一个错误,称
字段数错误
,可能是试图将它们解析为CSV内容

type myData struct {
  URL string `json:"url"`
}

func doWork() ([]myData, error) {
  rurl := "https://example.com/some.csv"
  out := make([]myData, 0)
  
  resp, err := http.Get(rurl)
  if err != nil {
    return []myData{}, err
  }

  defer resp.Body.Close()
  reader := csv.NewReader(resp.Body)
  reader.Comma = ','
  data, err := reader.ReadAll()
  if err != nil {
    return []myData{}, err
  }

  for _, row := range data {
    out = append(out, myData{URL: row[4]})
  }

  return out, nil
}

func main() {
  data, err := doWork()
  if err != nil {
    panic(err)
  }
  // do something with data
}

有没有办法跳过远程文件的前N行,或者让它忽略以#

开头的行好吧,方法很简单:不要试图将以“#”开头的行解释为CSV流的一部分;相反,将整个数据流视为两个流的连接:标题和实际CSV有效载荷。

最简单的方法可能是使用
bufio.Reader
能够从其底层流中读取行,并且它本身是一个
io.Reader
,因此您可以制作一个
csv.Reader
从它而不是源流中读取

因此,您可以这样滚动(不是真正的代码,未经测试):

导入(
“布菲奥”
“编码/csv”
“io”
“字符串”
)
函数解析(io.Reader)([]我的数据,错误)(
br:=bufio.NewReader(r)
变量行字符串
为了{
s、 错误:=br.ReadString('\n')
如果错误!=零{
返回零,错误
}
如果len(s)==0 | | s[0]!='#'{
直线=s
打破
}
}
//此时,line变量包含CSV流的第一行。
//让我们创建一个“多读取器”,它首先从该行读取
//然后-从CSV流的其余部分。
cr:=csv.NewReader(io.MultiReader(strings.NewReader(line),br))
cr.逗号=','
数据,错误:=cr.ReadAll()
如果错误!=零{
返回零,错误
}
对于_,行:=范围数据{
out=append(out,myData{URL:row[4]})
}
返回,零
}

< /代码> 嗯,方法很简单:不要尝试以''* ''作为CSV流的一部分来解释行,而是将整个数据流视为两个流的连接:标题和实际CSV有效载荷。

最简单的方法可能是使用
bufio.Reader
能够从其底层流中读取行,并且它本身是一个
io.Reader
,因此您可以制作一个
csv.Reader
从它而不是源流中读取

因此,您可以这样滚动(不是真正的代码,未经测试):

导入(
“布菲奥”
“编码/csv”
“io”
“字符串”
)
函数解析(io.Reader)([]我的数据,错误)(
br:=bufio.NewReader(r)
变量行字符串
为了{
s、 错误:=br.ReadString('\n')
如果错误!=零{
返回零,错误
}
如果len(s)==0 | | s[0]!='#'{
直线=s
打破
}
}
//此时,line变量包含CSV流的第一行。
//让我们创建一个“多读取器”,它首先从该行读取
//然后-从CSV流的其余部分。
cr:=csv.NewReader(io.MultiReader(strings.NewReader(line),br))
cr.逗号=','
数据,错误:=cr.ReadAll()
如果错误!=零{
返回零,错误
}
对于_,行:=范围数据{
out=append(out,myData{URL:row[4]})
}
返回,零
}

哦,实际上我刚刚意识到我可以添加以下内容:

reader.Comment = '#' // ignores the line starting with '#'

这与我当前的代码非常吻合,但感谢其他建议。

哦,实际上我刚刚意识到我可以添加以下内容:

reader.Comment = '#' // ignores the line starting with '#'

这与我当前的代码非常相配,但感谢其他建议。

谢谢,你能给我一个如何实现过滤器的建议吗?以#开头的行是我看到的许多csv文件中的注释。我认为这是标准的一部分。@WalterMitty:没有csv“标准”,有一个信息RFC4180,它根本没有提到注释,这意味着由解析应用程序来确定是否允许注释,以及语法是什么。(我忘记了go
csv。Reader
提供了一种方便配置过滤行的方法,在下面@c0nt0s0可以找到)谢谢,你能给我一个如何实现过滤器的建议吗?以#开头的行是我看到的许多csv文件中的注释。我认为这是标准的一部分。@WalterMitty:没有csv“标准”,有一个信息RFC4180,它根本没有提到注释,这意味着由解析应用程序来确定是否允许注释,以及语法是什么。(我忘记了go
csv。Reader
提供了一种方便配置过滤行的方法,在下面@c0nt0s0可以找到)不要犹豫,把你自己的答案标记为已接受。根据SO规则,这是完全正常的;-)谢谢!我会的,尽管SO告诉我必须等2天。不要犹豫,把你自己的答案标记为已接受。根据SO规则,这是完全正常的;-)谢谢!我会的,虽然这样说我得等两天。。