我想从 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/