Scala CSV解析器删除了空格

时间:2016-01-04 22:26:44

标签: regex scala csv

我正在尝试将以下行解析为数据数组:

"John,Doe","123 Main St","Brown Eyes"

我希望有一个数组data,如下所示:

data(0) = John,Doe
data(1) = 123 Main St
data(2) = Brown Eyes

我在网站上使用了以下CSV解析器:

import scala.util.parsing.combinator._

object CSV extends RegexParsers {
  override protected val whiteSpace = """[ \t]""".r

  def COMMA   = ","
  def DQUOTE  = "\""
  def DQUOTE2 = "\"\"" ^^ { case _ => "\"" }
  def CR      = "\r"
  def LF      = "\n"
  def CRLF    = "\r\n"
  def TXT     = "[^\",\r\n]".r

  def file: Parser[List[List[String]]] = repsep(record, CRLF) <~ opt(CRLF)
  def record: Parser[List[String]] = rep1sep(field, COMMA)
  def field: Parser[String] = (escaped|nonescaped)
  def escaped: Parser[String] = (DQUOTE~>((TXT|COMMA|CR|LF|DQUOTE2)*)<~DQUOTE) ^^ { case ls => ls.mkString("")}
  def nonescaped: Parser[String] = (TXT*) ^^ { case ls => ls.mkString("") }

  def parse(s: String) = parseAll(file, s) match {
    case Success(res, _) => res
    case _ => List[List[String]]()
  }
}

然后修剪所有空格。数据数组实际上看起来像:

data(0) = John,Doe
data(1) = 123MainSt
data(2) = BrownEyes

如何避免这种不必要的&#34;删除空格&#34;对于CSV解析器?谢谢!

4 个答案:

答案 0 :(得分:1)

你的代码说采取一系列转义或非转义代币并加入它们而没有中间空间:

...* ^^ { case ls => ls.mkString("") }

根据RegexParsers的文档,

  • 解析方法调用方法skipWhitespace(默认为true),如果为true,则在调用每个解析器之前跳过任何空格。
  • 受保护的val whiteSpace返回一个标识空格的正则表达式。

尝试关闭skipWhitespace

override protected val skipWhitespace = false

答案 1 :(得分:1)

有没有特别的理由手写CSV解码器而不是使用许多现有的,经过良好测试的解码器?与OpenCSVJackson CSV module一样。使用现有的lib应该简单得多,并且在尝试使用引号,修剪(或不修改)空格等时不会遇到各种问题。

答案 2 :(得分:1)

Robert Starling给出了问题的准确答案:将skipWhitespace设为false

“我如何可靠地解析CSV?”这个问题的答案,我假设你真正想知道的是“使用专用库”。

您可以使用Java之一 - opencsv,commons-csv,jackson-csv,univocity ......或其中一个Scala - 产品集合,purecsv,kantan.csv ......

不要在没有充分理由的情况下编写自己的文章 - 我写了表格,因为我需要比当时更好的类型处理 - 如果你这样做,不要使用其中一个Scala解析器组合库:它们加载解析前整个数据作为内存中的字符串,当数据开始增长时,它根本不会扩展。

如果必须编写自己的并且想要使用解析器组合库(因为,让我们面对它,这是一个有趣的问题而且这些库很酷),请考虑使用fastparse,或者使用parboiled,质量都比标准Scala高。

答案 3 :(得分:0)

您可以在一行中完成这项工作:

line.split((",(?=([^\"]*\"[^\"]*\")*[^\"]*$)")

正则表达式来自here,然后将其应用于文件的所有行。这将仅将逗号分隔为两个引号。

解析csv文件的代码:

scala> scala.io.Source.fromFile("toto.csv").getLines.toList.map(_.split((",(?=([^\"]*\"[^\"]*\")*[^\"]*$)"))