Parsec忽略除一个片段之外的所有内容

时间:2015-04-09 19:09:50

标签: html haskell parsec

我需要在格式不好的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执行此操作,还是建议我使用其他库?

3 个答案:

答案 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>"
]