8

在 Ruby 中,如果我有两个正则表达式,我可以创建另一个像这样的正则表达式:

a = /\d+/ # Matches digits
b = /\s+/ # Matches whitespaces
c = Regexp.union(a, b) # Matches sequences that consist only of digits or only of whitespaces

我想在 Scala 中做同样的事情,但我不知道如何做到这一点。请注意,我并不是在要求一种语法来创建字符类的联合,就像(\d+)|(\s+)在前面的示例中那样,我真的在寻找一种可能性,可以从两个给定的正则表达式创建一个新的正则表达式。

实际上,最后,我不会只为两个正则表达式而是大量。我不关心分组或任何事情,我只想知道字符串是否与给定正则表达式列表中的一个匹配。我可以在一个循环中检查所有这些,但这太低效了,这就是为什么我需要一个正则表达式来检查联合。

4

4 回答 4

9

Scala 使用基于类的 Java 正则表达式引擎java.util.regex.PatternPattern只有一种可以创建正则表达式的方法:

public static Pattern compile(String regex)

就是这样,Scala 没有给你任何相关的增强。

但是你可以做的一件事是在 match 语句中使用内置的联合,这里显示了捕获组,以防你想从字符串中提取一些东西:

val Dig = """(\d+)""".r
val Wsp = """(\s+)""".r

scala> "45" match { case Dig(_) | Wsp(_) => println("found"); case _ => }

成立

scala> "   " match { case Dig(_) | Wsp(_) => println("found"); case _ => }

成立

如果你真的想要一个组合的正则表达式,你必须在字符串级别进行。Pattern您可以使用 Scala 正则表达式获取 java .pattern,然后另一个.pattern获取字符串。大多数正则表达式都可以安全地包装起来(?:)以获得非捕获块,因此您可以像这样组合:

val Both = ("(?:"+Dig.pattern.pattern+")|(?:"+Wsp.pattern.pattern+")").r

但是,内部的任何捕获组将被表示,但未使用的分支将是null(不完全是编写惯用 Scala 的好方法,但无论如何,这是 Java 使用的):

scala> "2" match { case Both(d,w) => if (w!=null) println("white") else println(d) }
2

scala> " " match { case Both(d,w) => if (w!=null) println("white") else println(d) }
white
于 2012-12-11T16:11:57.053 回答
1

如果你想组合和重用正则表达式部分,我写了一个REL库/DSL 来做这件事。您的案例用法示例:

import fr.splayce.rel._
import Implicits._

val a: RE = "\\d+"
val b: RE = "\\s+"
val c: RE = a | b

c有一个r获取 Regex 对象的方法。它也在 中Implicits,因此您可以将其用作正则表达式,例如c findAllIn someText。如果需要,它将自动包装ab非捕获组。

如果你有一组正则表达式,你可以这样做reduceLeft

val regexes: List[RE] = List("a", "b", "c")
regexes.reduceLeft(_ | _)

附带说明:

  • 如果你导入Symbols._,你有一些简短的符号,比如\d\s
  • 它实现了大多数常用的正则表达式操作,以实现最大的可重用性

因此,使用 REL,您可以将第一个示例直接编写为:

val c = δ.+ | σ.+

它还提供了重用和组合相关提取器的方法。

如果您更喜欢香草斯卡拉,那么我对 Rex Kerr 的回答没有什么要补充的。

于 2012-12-11T17:33:27.637 回答
1

@akauppi 如果您想要一个正则表达式列表来匹配给定的字符串,您可以执行以下操作:

val regexes = List("\\d+".r, "\\s+".r, "a".r)
val single  = s"(${regexes.mkString("|")})".r
"123" match {
  case single(_*) = println("match")
  case _ => println("no match")
}
// above prints: match

"123  " match {
  case single(_*) = println("match")
  case _ => println("no match")
}
// above prints: no match

利用正则表达式列表的最佳方法是使用正则表达式表示法。这真的和说的一样

val single = "(\\d+|\\s+|a)".r
于 2017-09-13T05:36:22.757 回答
0

虽然这些答案可能有效,但它们可能有点过时或过于复杂。

val reg1 = "\\d+".r
val reg2 = "\\s+".r
val reg3 = s"${reg1}{$reg2}".r
"123  " match { 
    case reg3(_*) => println("match")
    case _ => println("no match")
 }
于 2016-01-20T11:24:07.680 回答