parsing - 用秒差距解析子字符串(通过忽略不匹配的前缀)

标签 parsing haskell parsec

我想从 git remote -v 的第一行中提取存储库名称,通常采用以下形式:

origin git@github.com:some-user/some-repo.git (fetch)

我使用 parsec 快速制作了以下解析器:

-- | Parse the repository name from the output given by the first line of `git remote -v`.
repoNameFromRemoteP :: Parser String
repoNameFromRemoteP = do
    _ <- originPart >> hostPart
    _ <- char ':'
    firstPart <- many1 alphaNum
    _ <- char '/'
    secondPart <- many1 alphaNum
    _ <- string ".git"
    return $ firstPart ++ "/" ++ secondPart
    where
      originPart = many1 alphaNum >> space
      hostPart =  many1 alphaNum
               >> (string "@" <|> string "://")
               >> many1 alphaNum `sepBy` char '.'

但是这个解析器看起来有点尴尬。实际上,我只对冒号(":")后面的内容感兴趣,如果我能为它编写一个解析器,那就更容易了。

有没有办法让parsec在匹配失败时跳过一个字符,然后从下一个位置重试?

最佳答案

如果我理解了这个问题,请尝试many (noneOf ":")。这将消耗任何字符,直到看到 ':',然后停止。

编辑:似乎我没有理解这个问题。您可以使用 try 组合器将可能在失败之前消耗一些字符的解析器转变为在失败时不消耗任何字符的解析器。所以:

skipUntil p = try p <|> (anyChar >> skipUntil p)

请注意,这在运行时(因为它将尝试在每个位置匹配 p)和内存(因为 try 阻止 p 不会消耗字符,因此在 p 完成之前根本无法对输入进行垃圾收集)。您可以通过参数化anyChar位来缓解这两个问题中的第一个问题,以便调用者可以选择一些便宜的解析器来查找候选位置;例如

skipUntil p skipper = try p <|> (skipper >> skipUntil p skipper)

然后,您可以使用上面的 many (noneOf ":") 结构,仅在以 : 开头的位置上尝试 p .

关于parsing - 用秒差距解析子字符串(通过忽略不匹配的前缀),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47208663/

相关文章:

haskell - 递归到 Haskell 中尚不存在的函数

c# - 在 C# 中解析 unicode 字符的字符串

java - 使用 Gson 将 JSON 反序列化为非静态嵌套类

ruby - 我如何在 Ruby 中标记这个字符串?

class - 非法实例声明

haskell - Jake Wheat 的 "Intro to Parsing with Parsec in Haskell"是否已过时?

json - 使用 Gson 和 JsonObject 格式化和解析数据

Haskell 将递归步骤保存到列表中

haskell - 使用镜头更新嵌套数据结构

haskell - Haskell 中的 Parsec 解析