Reputation: 53
I'm parsing a file and want to throw away certain lines of the file I'm not interested in. I've been able to get this to work for all cases except for when the last line is a throwaway and does not end in newline.
I've tried constructing an endOfInput
rule and joining it with a skipLine
rule via <|>
. This is all wrapped in a many
. Tweaking everything I seem to either get a 'many succeeds without consuming input...' error or a fail on the skipLine
rule when I don't try some kind of back track.
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."
** this errors out on the skipLine parser at the last line
I've tried
let skipLine = many (noneOf "\n") .>>? newline |>> fun x -> [string x]
... and ...
let skipLine = many (noneOf "\n") .>> newline |>> fun x -> [string x]
test (many (attempt skipLine <|> endOfInput)) "And here is the next.\nThen the last."
** these produce the many error
Note: the output functions are just place holders to get these to work with my other rules. I haven't gotten into figuring out how to format the output. This is my first time using FParsec and I'm new to F#.
Upvotes: 2
Views: 993
Reputation: 56
Here's an approach of parsing such a files with using an Option type, it'll help you to parse files with newlines in the end or skip blank lines in the middle. I've got the solution from that post - fparsec key-value parser fails to parse . Parsing of a text file with integer values in one column:
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() ))
Upvotes: 0
Reputation: 36688
FParsec actually has a built-in parser that does exactly what you're looking for: skipRestOfLine
. It terminates on either newlines or eof, just like what you're looking for.
If you want to try to implement it yourself as a learning exercise, let me know and I'll try to help you figure out the problem. But if you just want a parser that skips characters until the end of the line, the built-in skipRestOfLine
is exactly what you need.
Upvotes: 3