csv - 使用 Cassava 读取 CSV 列中的嵌套列表

标签 csv haskell

一个例子更容易解释,所以我想用木薯将此数据解析为数据类型

title;authors
Cambridge Economic History;Ian MorrisWalter,ScheidelRichard,P Saller

我尝试执行以下操作,但它不起作用(最小的不起作用示例):

{-# LANGUAGE OverloadedStrings, DeriveGeneric #-}

module Library where

import Data.Csv
import Data.List.Split
import qualified Data.Vector as V
import qualified Data.Text as T
import GHC.Generics

data Book = Book {
  title :: T.Text,
  authors :: Authors
} deriving (Generic, Show)

type Authors = [T.Text]

instance FromNamedRecord Book

instance FromNamedRecord Authors
parseField "authors" =
    pure $ splitOn "," ???
    
opts = defaultDecodeOptions {
  decDelimiter = fromIntegral (ord ';')
  }

main c = do
  csvData <- BL.readFile "data.csv"
  let res = decodeByNameWith opts csvData :: Either String (Header, V.Vector Book) 

可以用木薯来做吗?谢谢!

最佳答案

最简单的方法是编写自定义的 FromNamedRecord Book 的实例,而不是派生 Generic一。它看起来像:

instance FromNamedRecord Book where
  parseNamedRecord m = Book <$>
    m .: "title" <*>
    (T.splitOn "," <$> m .: "authors")

在这里,m .: "authors"将作者字段检索为 Text记录,以及 T.splitOn ","对该结果进行 fmapped ( <$> ) 以分割 Text进入[Text]以逗号分隔。

完整的程序:

{-# LANGUAGE OverloadedStrings #-}

module Library where

import Data.Char
import Data.Csv
import qualified Data.Vector as V
import qualified Data.Text as T
import Data.ByteString.Lazy as BL

data Book = Book {
  title :: T.Text,
  authors :: Authors
} deriving (Show)

type Authors = [T.Text]

instance FromNamedRecord Book where
  parseNamedRecord m = Book <$>
    m .: "title" <*>
    (T.splitOn "," <$> m .: "authors")

opts = defaultDecodeOptions {
  decDelimiter = fromIntegral (ord ';')
  }

main = do
  csvData <- BL.readFile "data.csv"
  let res = decodeByNameWith opts csvData :: Either String (Header, V.Vector Book)
  print res

给予:

λ> main
Right (["title","authors"],[Book {title = "Cambridge Economic History",
authors = ["Ian MorrisWalter","ScheidelRichard","P Saller"]}])

请注意,这不允许您处理作者列表中每个作者的引用,因此如果您需要使用嵌入的逗号来解析作者,例如:

Another Book;John Smith,"Anne Douglas, Jr."

你会不走运的。 Cassava 将拒绝解析像这样嵌入引号的“作者”字段,我认为您最终将不得不编写自己的专用 CSV 解析器。

关于csv - 使用 Cassava 读取 CSV 列中的嵌套列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67209738/

相关文章:

haskell - 为什么 "return Nothing"什么都不返回?

parsing - 如何使用 Parsec 通过特定字符串分隔字符串

bash - 如何修改以下 ps 命令以以逗号分隔值 (CSV) 格式打印?

ruby-on-rails - 如何在 Ruby on Rails 中读取基于编码的 CSV

python - 将大型 CSV 文件加载到 Oracle 表的技术选择

haskell - 如何覆盖 `doctest` 以使用我的 `ghc` ?

bash - 如何将一个列表(例如 2 和 3)上的数字与另一个列表(例如 5)上的近似和相匹配?

python - 重新组织 CSV,使日期不是列标题

function - 在 Haskell 中为给定的 `x^k*y^l` 和 `k` 生成所有可能数字 `l` 的流

Haskell - 使用自定义预处理器打包 cabal 包