我需要在格式不好的HTML文档中解析单个选择标记(因此基于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的样子。我如何使用Parsec执行此操作,还是建议我使用其他库?
答案 0 :(得分:2)
以下是我的表现:
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
答案 1 :(得分:1)
您可以尝试使用正则表达式并捕获选择标记:
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
答案 2 :(得分:0)
您可以使用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>"
]