簡體   English   中英

Scala CSV解析器刪除了空格

[英]Scala CSV parser removed spaces

我正在嘗試將以下行解析為數據數組:

"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

如何避免CSV解析器出現這種不必要的“刪除空格”? 謝謝!

您的代碼說要采用一系列轉義或不轉義的令牌,並在中間插入空格:

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

根據RegexParsers的文檔,

  • 解析方法調用方法skipWhitespace(默認為true),如果為true,則在調用每個解析器之前跳過任何空格。
  • 受保護的val whiteSpace返回用於標識空白的正則表達式。

嘗試關閉skipWhitespace

override protected val skipWhitespace = false

手寫CSV解碼器而不是使用許多現有的,經過良好測試的解碼器有什么特殊的原因嗎? OpenCSVJackson CSV module 使用現有的lib應該更簡單,並且在嘗試取消轉義引號,修剪(或不修剪)空格等時,您不會遇到各種問題。

Robert Starling給出了您問題的准確答案:將skipWhitespace設置為false

我假設您真正想知道的問題“如何可靠地解析CSV?”的答案是“使用專用庫”。

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

不要在沒有充分理由的情況下編寫自己的文件-我寫了表格,是因為我需要比當時更好的類型處理-如果這樣做,請不要使用Scala解析器組合器庫之一:它們將整個數據加載為解析之前在內存中的字符串,當數據開始增長時,它根本不會縮放。

如果您必須編寫自己的文件並想使用解析器組合器庫(因為,面對現實,這是一個有趣的問題,並且那些庫很酷),請考慮使用fastparse或將其parboiled,它們的質量都比標准Scala高一。

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

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

正則表達式來自此處 ,然后將其應用於文件的所有行。 這只會將逗號分隔為兩個引號之外。

解析csv文件的代碼:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM