【问题标题】:With FParsec how would I parse: line ending in newline <|> a line ending with eof使用 FParsec 我将如何解析:以换行符 <|> 结尾的行以 eof 结尾的行
【发布时间】:2019-08-13 20:33:10
【问题描述】:

我正在解析一个文件,并想丢弃我不感兴趣的文件中的某些行。我已经能够让它适用于所有情况,除了最后一行是一次性的并且确实不以换行符结尾。

我尝试构建一个endOfInput 规则并通过&lt;|&gt; 将它与skipLine 规则连接起来。这一切都包含在many 中。当我不尝试某种回溯时,调整所有我似乎要么得到“许多成功而不消耗输入......”错误或 skipLine 规则失败。

let skipLine = many (noneOf "\n") .>> newline |>> fun x -> [string x]

let endOfInput = many (noneOf "\n") .>> eof |>> fun x -> [string x]

test (many (skipLine <|> endOfInput)) "And here is the next.\nThen the last."

** 在最后一行的 skipLine 解析器上出现此错误

我试过了

let skipLine = many (noneOf "\n") .>>? newline |>> fun x -> [string x]

...和...

let skipLine = many (noneOf "\n") .>> newline |>> fun x -> [string x]

test (many (attempt skipLine <|> endOfInput)) "And here is the next.\nThen the last."

** 这些会产生很多错误

注意:输出函数只是让它们与我的其他规则一起使用的占位符。我还没有弄清楚如何格式化输出。 这是我第一次使用 FParsec,我是 F# 新手。

【问题讨论】:

    标签: f# fparsec


    【解决方案1】:

    FParsec 实际上有一个内置解析器,可以完全满足您的需求:skipRestOfLine。它在换行符或 eof 处终止,就像您要查找的内容一样。

    如果您想尝试自己将其作为学习练习来实施,请告诉我,我会尽力帮助您找出问题所在。但是,如果您只想要一个可以跳过字符直到行尾的解析器,那么内置的skipRestOfLine 正是您所需要的。

    【讨论】:

    • 感谢您的建议。我以前使用过 skipRestOfLine 并最终遇到了“许多”错误,但在您提出建议后,我决定再试一次。这次将 2 条规则合二为一: let skipLine = (skipRestOfLine false) .>>?换行符 |>> fun x-> [string x] 成功了!谢谢!这几天我一直在咀嚼这个。
    • ...对于可能看到此内容的其他人。我也尝试过直接(skipRestOfLine true),但这让我回到了“许多成功而不消耗输入......”错误。
    • 只要let skipLine = (skipRestOfLine true) 应该 已经是你所需要的了。如果您遇到“许多成功但不消耗输入”错误,那可能是因为您正在执行many (attempt skipLine) 而不仅仅是many skipLine,尽管如果不查看所有代码就很难确定。您似乎还没有完全理解 quanttec.com/fparsec/tutorial.html#parsing-alternatives — 您可能会从返回并重新阅读 FParsec 教程的那部分中受益,旨在更好地了解 FParsec 的回溯如何详细工作。
    • test (many (skipRestOfLine true)) "这是下一个。\n然后是最后一个。" 其中测试函数与教程中使用的相同。它产生许多错误。我认为教程或文档中有警告。但是你是对的,我还没有掌握一些概念——当一些解析器实际上“消耗”输入时,以及解析器状态何时/如何改变是一个大问题。我只是需要花更多的时间来处理它。
    【解决方案2】:

    这是一种使用 Option 类型解析此类文件的方法, 它将帮助您解析最后带有换行符的文件或跳过中间的空白行。我从那篇帖子中得到了解决方案 - fparsec key-value parser fails to parse 。解析一列中具有整数值的文本文件:

    module OptionIntParser =
     open FParsec
     open System
     open System.IO
      
     let pCell: Parser<int, unit> = pint32 |>> fun x -> x
     let pSome =   pCell |>> Some
     let pNone =  (restOfLine false) >>% None
     let pLine = (attempt pSome) <|> pNone
     let pAllover = sepBy pLine newline  |>> List.choose id
    
     let readFile filePath =
        let rr = File.OpenRead(filePath)    
        use reader = new IO.StreamReader(rr)    
        reader.ReadToEnd()
    
     let testStr = readFile("./test1.txt")
    
     let runAll s  =
      let res = run pAllover s in
        match res with
         | Success (rows, _, _) ->  rows 
         | Failure (s, _, _) -> []
    
     let myTest =
       let res = runAll testStr
       res |> List.iter (fun (x) -> Console.WriteLine(x.ToString() ))
    

    【讨论】:

      猜你喜欢
      • 2022-12-19
      • 1970-01-01
      • 2018-05-08
      • 2010-09-07
      • 1970-01-01
      • 1970-01-01
      • 2017-10-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多