在 Haskell 中使用 parsec 或 attoparsec 在两个字符串之间进行非贪婪匹配

Coo*_*Bro 2 regex parsing haskell

这是我正在努力解决的问题。

使用像parsec或这样的解析器组合器attoparsec,我想在以下字符串中匹配“匹配我”

“在这个字符串匹配我之前匹配我之前匹配我之前匹配我之前的噪音匹配”

其中front noise, match me,back noise可以是任何字符串

这是该问题解决方案的正则表达式版本:

(?<=match after this string)(.*?)(?=match before me)
Run Code Online (Sandbox Code Playgroud)

如您所见,它是非贪婪的(.*?)。换句话说,它不会像“在我之前匹配我匹配”那样匹配(.*)

为了记录,这里是我的许多悲惨尝试中的一些

在 parsec 中有between,但我对如何使用它感到困惑。它的文档有示例braces = between (symbol "{") (symbol "}"),但我什至无法让示例本身正常工作。

我也尝试过诸如between (string "start") (many anyChar) (string "end")“开始比赛结束”之类的事情,但它也不起作用:

unexpected " "
expecting "end"
Run Code Online (Sandbox Code Playgroud)

我尝试过的另一件事是,这当然不会产生任何噪音:

(string "start") *> (many anyChar) <* (string "end")
Run Code Online (Sandbox Code Playgroud)

但它也不起作用:

Prelude Control.Applicative Text.Parsec P> let betw = (string "start") *> (many anyChar) <* (string "end")
Prelude Control.Applicative Text.Parsec P> test betw "start match end"
Left (line 1, column 16):
unexpected end of input
expecting "end"
Run Code Online (Sandbox Code Playgroud)

经过几十年的实验,我开始尝试像

manyTill anyChar (string "start") 关于“噪音开始比赛结束”

unexpected " "
expecting "start"
Run Code Online (Sandbox Code Playgroud)

kos*_*kus 5

我同意您可能希望采用更高级别方法的评论。

不过,可以使用 parsec 以这种方式解决它,您几乎就可以了。使用manyTill作品,但它在开始时还不匹配噪音。所以使用它两次:

GHCi> let test = manyTill anyChar (string "start") *> manyTill anyChar (string "end")
GHCi> parseTest test "foo start match end"
" match "
Run Code Online (Sandbox Code Playgroud)

不过还是有问题:

GHCi> parseTest test "noise start match end"
parse error at (line 1, column 5):
unexpected "e"
expecting "tart"
Run Code Online (Sandbox Code Playgroud)

Parsec 默认不会回溯,所以看到sinnoise会让 Parsec 期待start. 为了防止这种情况,您必须同时使用try两个“分隔符”:

GHCi> let test = manyTill anyChar (try $ string "start") *> manyTill anyChar (try $ string "end")
GHCi> parseTest test "noise start match end"
" match "
Run Code Online (Sandbox Code Playgroud)