使用 foldLine 解析多个块
Parsing many blocks with foldLine
对于这个简化的问题,我正在尝试解析看起来像
的输入
foo bar
baz quux
woo
hoo xyzzy
glulx
进入
[["foo", "bar", "baz", "quux", "woo"], ["hoo", "xyzzy", "glulx"]]
我试过的代码如下:
import qualified Text.Megaparsec.Lexer as L
import Text.Megaparsec hiding (space)
import Text.Megaparsec.Char hiding (space)
import Text.Megaparsec.String
import Control.Monad (void)
import Control.Applicative
space :: Parser ()
space = L.space (void spaceChar) empty empty
item :: Parser () -> Parser String
item sp = L.lexeme sp $ some letterChar
items :: Parser () -> Parser [String]
items sp = L.lineFold sp $ \sp' -> some (item sp')
items_ :: Parser [String]
items_ = items space
这适用于 items
的一个块:
λ» parseTest items_ "foo bar\n baz quux\n woo"
["foo","bar","baz","quux","woo"]
但是当我尝试解析 many items
时,它在第一个未缩进的行上失败了:
λ» parseTest (many items_) "foo bar\n baz quux\n woo\nhoo xyzzy\n glulx"
4:1:
incorrect indentation (got 1, should be greater than 1)
或者,输入更简单:
λ» parseTest (many items_) "a\nb"
2:1:
incorrect indentation (got 1, should be greater than 1)
Megaparsec 的作者在这里 :-) 使用时要记住一件事
Megaparsec 是它的词法分析器模块是故意“低级”的。它
不做任何你不能建立自己的事情,它不会把你锁在任何
特定的“框架”。所以基本上在你的情况下你有 space 消费者
sp'
为您提供,但您应该小心使用它,因为它肯定
当您的缩进级别小于或等于缩进级别时失败
整个折叠的开始,顺便说一下,这就是你的折叠结束的方式。
引用the docs:
Create a parser that supports line-folding. The first argument is used to
consume white space between components of line fold, thus it must consume
newlines in order to work properly. The second argument is a callback that
receives custom space-consuming parser as argument. This parser should be
used after separate components of line fold that can be put on different
lines.
sc = L.space (void spaceChar) empty empty
myFold = L.lineFold sc $ \sc' -> do
L.symbol sc' "foo"
L.symbol sc' "bar"
L.symbol sc "baz" -- for the last symbol we use normal space consumer
折叠不能无限期地 运行 所以你应该预料到它会因错误而失败
类似于您现在拥有的消息。要想成功,你应该思考
关于它完成的方法。这通常是通过使用“正常”来完成的
space消费者行尾折叠:
space :: Parser ()
space = L.space (void spaceChar) empty empty
item :: Parser String
item = some letterChar
items :: Parser () -> Parser [String]
items sp = L.lineFold sp $ \sp' ->
item `sepBy1` try sp' <* sp
items_ :: Parser [String]
items_ = items space
item `sepBy1` try sp'
运行s 直到它失败然后 sp
抓住剩下的,所以
可以解析下一个折叠。
λ> parseTest items_ "foo bar\n baz quux\n woo"
["foo","bar","baz","quux","woo"]
λ> parseTest (many items_) "foo bar\n baz quux\n woo\nhoo xyzzy\n glulx"
[["foo","bar","baz","quux","woo"],["hoo","xyzzy","glulx"]]
λ> parseTest (many items_) "foo bar\n baz quux\n woo\nhoo\nxyzzy\n glulx"
[["foo","bar","baz","quux","woo"],["hoo"],["xyzzy","glulx"]]
对于这个简化的问题,我正在尝试解析看起来像
的输入foo bar
baz quux
woo
hoo xyzzy
glulx
进入
[["foo", "bar", "baz", "quux", "woo"], ["hoo", "xyzzy", "glulx"]]
我试过的代码如下:
import qualified Text.Megaparsec.Lexer as L
import Text.Megaparsec hiding (space)
import Text.Megaparsec.Char hiding (space)
import Text.Megaparsec.String
import Control.Monad (void)
import Control.Applicative
space :: Parser ()
space = L.space (void spaceChar) empty empty
item :: Parser () -> Parser String
item sp = L.lexeme sp $ some letterChar
items :: Parser () -> Parser [String]
items sp = L.lineFold sp $ \sp' -> some (item sp')
items_ :: Parser [String]
items_ = items space
这适用于 items
的一个块:
λ» parseTest items_ "foo bar\n baz quux\n woo"
["foo","bar","baz","quux","woo"]
但是当我尝试解析 many items
时,它在第一个未缩进的行上失败了:
λ» parseTest (many items_) "foo bar\n baz quux\n woo\nhoo xyzzy\n glulx"
4:1:
incorrect indentation (got 1, should be greater than 1)
或者,输入更简单:
λ» parseTest (many items_) "a\nb"
2:1:
incorrect indentation (got 1, should be greater than 1)
Megaparsec 的作者在这里 :-) 使用时要记住一件事
Megaparsec 是它的词法分析器模块是故意“低级”的。它
不做任何你不能建立自己的事情,它不会把你锁在任何
特定的“框架”。所以基本上在你的情况下你有 space 消费者
sp'
为您提供,但您应该小心使用它,因为它肯定
当您的缩进级别小于或等于缩进级别时失败
整个折叠的开始,顺便说一下,这就是你的折叠结束的方式。
引用the docs:
Create a parser that supports line-folding. The first argument is used to consume white space between components of line fold, thus it must consume newlines in order to work properly. The second argument is a callback that receives custom space-consuming parser as argument. This parser should be used after separate components of line fold that can be put on different lines.
sc = L.space (void spaceChar) empty empty
myFold = L.lineFold sc $ \sc' -> do
L.symbol sc' "foo"
L.symbol sc' "bar"
L.symbol sc "baz" -- for the last symbol we use normal space consumer
折叠不能无限期地 运行 所以你应该预料到它会因错误而失败 类似于您现在拥有的消息。要想成功,你应该思考 关于它完成的方法。这通常是通过使用“正常”来完成的 space消费者行尾折叠:
space :: Parser ()
space = L.space (void spaceChar) empty empty
item :: Parser String
item = some letterChar
items :: Parser () -> Parser [String]
items sp = L.lineFold sp $ \sp' ->
item `sepBy1` try sp' <* sp
items_ :: Parser [String]
items_ = items space
item `sepBy1` try sp'
运行s 直到它失败然后 sp
抓住剩下的,所以
可以解析下一个折叠。
λ> parseTest items_ "foo bar\n baz quux\n woo"
["foo","bar","baz","quux","woo"]
λ> parseTest (many items_) "foo bar\n baz quux\n woo\nhoo xyzzy\n glulx"
[["foo","bar","baz","quux","woo"],["hoo","xyzzy","glulx"]]
λ> parseTest (many items_) "foo bar\n baz quux\n woo\nhoo\nxyzzy\n glulx"
[["foo","bar","baz","quux","woo"],["hoo"],["xyzzy","glulx"]]