Scala正则表达式多个块捕获

8

我想在Scala中使用正则表达式捕获多行字符串的部分。 输入的格式为:

val input = """some text
              |begin {
              |  content to extract
              |  content to extract
              |}
              |some text
              |begin {
              |  other content to extract
              |}
              |some text""".stripMargin

我尝试了几种方法来获取位于 begin { } 块中的文本。其中之一:

val Block = """(?s).*begin \{(.*)\}""".r

input match {
  case Block(content) => println(content)
  case _ => println("NO MATCH")
}

我得到了一个“NO MATCH”。如果我去掉“\}”,那么正则表达式看起来像“(?s)。*begin \{(.*)”,它将匹配包括不需要的“}”和“some text”的最后一个块。我在rubular.com上检查了我的正则表达式,如/.*begin \{(.*)\}/m,它至少匹配一个块。我以为当我的Scala正则表达式匹配相同的内容时,我就可以开始使用findAllIn来匹配所有块。我做错了什么?
我看了一下Scala Regex enable Multiline option,但我无法捕获例如Seq[String]中的所有文本块的出现。 任何帮助都将不胜感激。
3个回答

11

正如Alex所说,使用模式匹配从正则表达式中提取字段时,模式会像边界一样作用(即使用^$)。通常避免这个问题的方法是先使用findAllIn。这样:

val input = """some text
              |begin {
              |  content to extract
              |  content to extract
              |}
              |some text
              |begin {
              |  other content to extract
              |}
              |some text""".stripMargin

val Block = """(?s)begin \{(.*)\}""".r

Block findAllIn input foreach (_ match {
  case Block(content) => println(content)
  case _ => println("NO MATCH")
})

否则,您可以在开头和结尾使用.*来避免这个限制:

val Block = """(?s).*begin \{(.*)\}.*""".r

input match {
  case Block(content) => println(content)
  case _ => println("NO MATCH")
}

顺便提一下,您可能需要一个非贪婪匹配器:

val Block = """(?s)begin \{(.*?)\}""".r

Block findAllIn input foreach (_ match {
  case Block(content) => println(content)
  case _ => println("NO MATCH")
})

你知道这个有没有记录在哪里吗? - Alex Neth
Alex,此时此刻我也不确定。我在Regex方面做了很多事情,甚至扩展了库,以至于我甚至无法回忆起库提供了什么!例如,当我发现这种方法不存在于库中时,我正要编写Block findAllMatchesIn input map (_ group 0) - Daniel C. Sobral
2
对于(Block(content)<- Block findAllIn input),println(content)。 - Ken Bloom
1
谢谢,肯恩。我应该想到提供至少一个for-comprehension的例子。在左侧进行模式匹配是聪明的做法。 - Daniel C. Sobral

1

在进行匹配时,我认为隐含需要完全匹配。您的匹配相当于:

val Block = """^(?s).*begin \{(.*)\}$""".r

如果在结尾添加 .*,它就能正常工作:

val Block = """(?s).*begin \{(.*)\}.*""".r

我还没有找到任何关于这个的文档,但是我也遇到了同样的问题。


0
作为其他答案的补充,我想指出kantan.regex的存在,它让你可以编写以下内容:
import kantan.regex.ops._

// The type parameter is the type as which to decode results,
// the value parameters are the regular expression to apply and the group to
// extract data from.
input.evalRegex[String]("""(?s)begin \{(.*?)\}""", 1).toList

这将产生:

List(Success(
  content to extract
  content to extract
), Success(
  other content to extract
))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接