Parsec 解析字符串 `sepBy` endline

Parsec parse string `sepBy` endline

我在解析简单字符串时遇到了 parsec 的奇怪行为

字符串示例是:

  1 C1           1.1650     2.7470    -0.1840 ca         1 MOL       0.408200
  2 N1          -0.0550     2.1750    -0.0380 nb         1 MOL      -0.665000
  3 C2          -0.2180     0.8450     0.1920 ca         1 MOL       0.450600
  4 C3          -1.6310     0.3330     0.3310 c3         1 MOL      -0.140700

我的解析器是

atom = do
    str <- optional spaces *> (many1 $ (letter <|> digit <|> oneOf "-+.")) `sepBy` spaces

    let id = read $ head str :: Int
    let charge = (read.head.reverse) str :: Double    
    return (id,(str !! 1),charge)

records = atom `sepEndBy1` newline  

我需要用 atom 解析器解析每个字符串。如果我只对一行使用原子解析器,它就可以工作。

但是如果尝试使用 records 解析器,看起来第一个原子解析器会吃掉整个字符串。所以我有 (1,C1,-0.140700) 而不是数组 [(1,C1,-0.408200),(2,N1,0.665000)]

P.S。在这种情况下,我根本无法理解 parsec 如何遍历带有 \n 符号的线。例如,如果我们有

onlyForTest = (many1 $ (letter <|> digit <|> oneOf "-+.")) `sepBy` spaces

并测试这样的例子:

*Main> parseTest onlyForTest  "bla bl\na bla"

输出:

["bla","bl","a","bla"]

但是 \n 符号不是 sepBy!

中的分隔符

正如@freestyle 所说,spaces 使用 Data.Char.isSpace 来确定是否应该消耗一个字符,这包括 \n\r

使用 oneOf " \t" 代替 spaces,使用 endOfLine 代替 newline。哦,optionaloptional spaces 中是无关紧要的,因为 spaces 消耗 零个或更多 个字符。