Parsec 忽略除一个片段之外的所有内容
Parsec ignore everything except one fragment
我需要解析格式不正确的 HTML 文档中的单个 select 标记(因此基于 XML 的解析器不起作用)。
我想我知道如何在到达那里后使用 parsec 来解析 select 标记,但是如何跳过该标记前后的所有内容?
示例:
<html>
random content with lots of tags...
<select id=something title="whatever"><option value=1 selected>1. First<option value=2>2. Second</select>
more random content...
</html>
这实际上就是 HTML 在 select 标签中的样子。我如何使用 Parsec 执行此操作,或者您会推荐我使用其他库吗?
这是我的做法:
solution = (do {
; string "<tag-name"
; x <- ⟦insertOptionsParserHere⟧
; char '>'
; return x
}) <|> (anyChar >> solution)
这将递归地使用字符,直到遇到起始 <html>
标记,然后使用您的解析器,并在使用最终标记时离开递归。
明智的做法是注意前后可能有尾随空格要解决这个问题,我们可以这样做,前提是您的解析器使用标签:
solution = ⟦insertHtmlParserHere⟧ <|> (anyChar >> solution)
要清楚这意味着 ⟦insertHtmlParserHere⟧
将具有这种结构:
⟦insertHtmlParserHere⟧ = do
string "<tag-name"
⋯
char '>'
附带说明一下,如果您想捕获每个可用的标签,您可以非常愉快地使用 many
:
everyTag = many solution
您可以尝试使用正则表达式并捕获 select 标签:
import Text.ParserCombinators.Parsec
import Text.Regex.Posix
getOptionTags content = content =~ "(<select.*</select>)"::[[String]]
main :: IO ()
main = do
s <- readFile "in"
putStrLn . show . head . head $ getOptionTags s
您可以使用 Replace.Megaparsec.findAll
在文档中查找与解析器匹配的子字符串。
import Replace.Megaparsec
import Text.Megaparsec
let parseSelect :: Parsec Void String String
parseSelect = do
chunk "<select"
manyTill anySingle $ chunk "</select>"
let input = "<html>\n random content with lots of tags...\n <select id=something title=\"whatever\"><option value=1 selected>1. First<option value=2>2. Second</select>\n more random content...\n</html>"
>>> parseTest (findAll parseSelect) input
[Left "<html>\n random content with lots of tags...\n "
,Right "<select id=something title=\"whatever\"><option value=1 selected>1. First<option value=2>2. Second</select>"
,Left "\n more random content...\n</html>"
]
我需要解析格式不正确的 HTML 文档中的单个 select 标记(因此基于 XML 的解析器不起作用)。
我想我知道如何在到达那里后使用 parsec 来解析 select 标记,但是如何跳过该标记前后的所有内容?
示例:
<html>
random content with lots of tags...
<select id=something title="whatever"><option value=1 selected>1. First<option value=2>2. Second</select>
more random content...
</html>
这实际上就是 HTML 在 select 标签中的样子。我如何使用 Parsec 执行此操作,或者您会推荐我使用其他库吗?
这是我的做法:
solution = (do {
; string "<tag-name"
; x <- ⟦insertOptionsParserHere⟧
; char '>'
; return x
}) <|> (anyChar >> solution)
这将递归地使用字符,直到遇到起始 <html>
标记,然后使用您的解析器,并在使用最终标记时离开递归。
明智的做法是注意前后可能有尾随空格要解决这个问题,我们可以这样做,前提是您的解析器使用标签:
solution = ⟦insertHtmlParserHere⟧ <|> (anyChar >> solution)
要清楚这意味着 ⟦insertHtmlParserHere⟧
将具有这种结构:
⟦insertHtmlParserHere⟧ = do
string "<tag-name"
⋯
char '>'
附带说明一下,如果您想捕获每个可用的标签,您可以非常愉快地使用 many
:
everyTag = many solution
您可以尝试使用正则表达式并捕获 select 标签:
import Text.ParserCombinators.Parsec
import Text.Regex.Posix
getOptionTags content = content =~ "(<select.*</select>)"::[[String]]
main :: IO ()
main = do
s <- readFile "in"
putStrLn . show . head . head $ getOptionTags s
您可以使用 Replace.Megaparsec.findAll
在文档中查找与解析器匹配的子字符串。
import Replace.Megaparsec
import Text.Megaparsec
let parseSelect :: Parsec Void String String
parseSelect = do
chunk "<select"
manyTill anySingle $ chunk "</select>"
let input = "<html>\n random content with lots of tags...\n <select id=something title=\"whatever\"><option value=1 selected>1. First<option value=2>2. Second</select>\n more random content...\n</html>"
>>> parseTest (findAll parseSelect) input
[Left "<html>\n random content with lots of tags...\n "
,Right "<select id=something title=\"whatever\"><option value=1 selected>1. First<option value=2>2. Second</select>"
,Left "\n more random content...\n</html>"
]