使用 Parsec,如何解析零个或多个以 foo2 结尾且全部由点分隔的 foo1?

发布于 2024-08-24 06:20:37 字数 453 浏览 8 评论 0 原文

我想做的事情看起来很简单,但由于我是一个秒差距 Haskell 新手,所以解决方案让我困惑。

我有两个解析器,比如说 foo1foo2,其中 foo1 可以解析中间项,foo2 解析结尾学期。术语由符号 "." 分隔。

我需要解析的句子有

  • foo2
  • foo1.foo2
  • foo1.foo1.foo2

等等。

我最初的想法是这样做

do k <- sepBy foo1 (char'.')
   j <- foo2

,但这并不能捕获仅 foo2 的情况。

What I am trying to do seems pretty simple, but since I am a parsec Haskell newb, the solution is eluding me.

I have two parsers, let's say foo1 and foo2 where foo1 can parse a intermedate term and foo2 parses an ending term. Terms are separated by a symbol, ".".

Sentences that I need to parse are

  • foo2
  • foo1.foo2
  • foo1.foo1.foo2

and so on.

My original thought was to do

do k <- sepBy foo1 (char'.')
   j <- foo2

but that wouldn't catch the foo2-only case.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

萌梦深 2024-08-31 06:20:37

您需要 endBy,而不是 sepBy

foo = do k <- foo1 `endBy` char '.'
         j <- foo2
         ... 

这将强制在每次出现 foo1 后出现分隔符。

当然,endBy 可以简单地替换为 many,这可能会更清楚。

foo = do k <- many $ foo1 <* char '.' 
         j <- foo2
         ...

或者,没有 Control.Applicative

foo = do k <- many $ do x <- foo1; char '.'; return x
         j <- foo2
         ...

You want endBy, not sepBy.

foo = do k <- foo1 `endBy` char '.'
         j <- foo2
         ... 

That will force the separator to be present after each occurrence of foo1.

Of course, endBy is trivially replaceable by many, which may be clearer.

foo = do k <- many $ foo1 <* char '.' 
         j <- foo2
         ...

or, without Control.Applicative:

foo = do k <- many $ do x <- foo1; char '.'; return x
         j <- foo2
         ...
余生共白头 2024-08-31 06:20:37

首先,您需要 endBy 而不是 sepBy

do k <- endBy foo1 (char'.')
   j <- foo2

其次,它会

捕获 foo2 案例

文档

endBy p sep 解析零个或多个出现的 p,以 sep 分隔。返回p返回的值的列表。

First, you want endBy instead of sepBy:

do k <- endBy foo1 (char'.')
   j <- foo2

Second, it would

catch the just foo2 case

From the documentation:

endBy p sep parses zero or more occurrences of p, separated by sep. Returns a list of values returned by p.

玻璃人 2024-08-31 06:20:37

尝试类似的东西

many (foo1 >>= (\v -> char '.' >> return v)) >>= \v1 ->
  foo2 >>= \v2 ->
  -- ...
  -- combine v1 & v2 somehow

(当然,只是一个草图。)

一般来说,many 组合器相当于 Parsec 的 克林星;如果您要向现有解析器添加一些简单的内容(例如尾随点),那么使用 >> / >>= 实际上可能更干净、更简单而不是使用 do 表示法。

Try something like

many (foo1 >>= (\v -> char '.' >> return v)) >>= \v1 ->
  foo2 >>= \v2 ->
  -- ...
  -- combine v1 & v2 somehow

(Just a sketch, of course.)

In general, the many combinator is Parsec's equivalent of Kleene star; and if you're going to add something simple like a trailing dot to an existing parser, using >> / >>= may actually be cleaner and simpler than using do notation.

怀中猫帐中妖 2024-08-31 06:20:37

当然,它会捕获 foo2 的情况。用于你的 foo1,莱顿的话:

let a = sepBy word (char '.')
parseTest a "foo.bar.baz"
parseTest a "foo"
parseTest a ".baz"

sure, it would catch the foo2 case. Using for your foo1, Leiden's word:

let a = sepBy word (char '.')
parseTest a "foo.bar.baz"
parseTest a "foo"
parseTest a ".baz"
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文