Scala正则表达式模式匹配无法使其工作

时间:2013-08-05 06:54:09

标签: regex scala

我正在尝试使用点分隔字符串来编写正则表达式。例如,

"abc", "abc.def", "a.b.c.e.f" 

都有效,但

"abc..def", ".abc", "abc." 

无效

这是我在scala中的正则表达式代码

object Test {
  def main(args: Array[String]) {

    val TestPattern = "^([a-z]+)(\\.?[a-z]+)*".r
    val x: String = "abc.def.hij"

    x match {
      case TestPattern(a,b) => println(a + b)
      case _ => println("Not Found")
    }
  }
}

所以这是我的正则表达式,

"^([a-z]+)(\\.?[a-z]+)*".r

有两个组成部分,

1. Starts with a-z
2. Repeat (has 0 or 1 dot, one or more from a-z) zero or more times

但是,

Input: abc.def.hij
Output: abc.hij

我不明白为什么

.def

不会显示在我的输出中。

3 个答案:

答案 0 :(得分:2)

使用重复的组,您只能获得最后一场比赛。

要全部使用,请使用findFirstMatchIn或类似内容。

肯定有重复的问题。

scala> val r0 = "([a-z]+)".r.unanchored
r0: scala.util.matching.UnanchoredRegex = ([a-z]+)

scala> val m0 = r0 findFirstMatchIn x
m0: Option[scala.util.matching.Regex.Match] = Some(abc)

scala> val r1 = "(\\.?[a-z]+)".r.unanchored
r1: scala.util.matching.UnanchoredRegex = (\.?[a-z]+)

scala> val m1 = r1 findFirstMatchIn m0.get.after
m1: Option[scala.util.matching.Regex.Match] = Some(.def)

scala> r1 findFirstMatchIn m1.get.after
res2: Option[scala.util.matching.Regex.Match] = Some(.hij)

答案 1 :(得分:1)

如同其他答案中所示,您将始终获得多次匹配的组的最后一场比赛。这是底层Java正则表达式引擎的限制。

在您的情况下,首先拆分值并评估各个组可能更好:

    scala> val nameSeparator="""\.""".r
    nameSeparator: scala.util.matching.Regex = \.

    scala> val namePart="""[a-z]+""".r
    namePart: scala.util.matching.Regex = [a-z]+


    scala> val parts=nameSeparator.split("abc.def.ghi")
    parts: Array[String] = Array(abc, def, ghi)

    scala> parts.forall(!namePart.unapplySeq(_).isEmpty)
    res20: Boolean = true

最后一个表达式检查数组部分中的所有元素是否与正则表达式namePart匹配。

如果你有一个更复杂的问题(例如表达式以前缀开头,那么有多个组具有不同的分隔符,然后是后缀),最好直接切换到解析器组合器:

    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    import scala.util.parsing.combinator.RegexParsers

    object NameParser extends RegexParsers {
      def separator : Parser[String] = """\.""".r
      def namePart : Parser[String] = """[a-z]+""".r
      def name : Parser[List[String]] = repsep(namePart, separator)

      def apply(input: String) = parseAll(name, input)
    }

    // Exiting paste mode, now interpreting.

    import scala.util.parsing.combinator.RegexParsers
    defined module NameParser

    scala> NameParser("abc.def.ghi")
    res24: NameParser.ParseResult[List[String]] = [1.12] parsed: List(abc, def, ghi)

该示例可以很容易地适应更复杂的解析器。如果你需要一些错误处理,解析器组合器可以比正则表达式更容易扩展。

答案 2 :(得分:0)

您可以捕获完整组以及最后一组:

    object Test {
      def main(args: Array[String]) {

          val TestPattern = """^([a-z]+(\.[a-z]+)*)""".r
          val x = "abc.def.hij"

          x match {
            case TestPattern(a, b) => println(a)
            case _ => println("Not Found")
          }
      }
    }
  

编辑:

     
      
  1. 在三引号字符串中,不需要转义字符,因此   一个反斜杠就可以了。

  2.   
  3. “case TestPattern(a)”不起作用,因为参数数量必须与捕获组数量相同。
      每个开放式paranthesis都会启动一个新的捕获组。   例如“”“^([a-z] +(\。[a-z] +))”“”。r有2个捕获组,   “”(^ [([a-z] +(\。[a-z] +)))“”“。r有3。   所以后者将与TestPattern(a,b,c)匹配。

  4.   
  5. 由于在这种情况下不需要第二个捕获组,我们可以使用非捕获组,它以(?:而不是(。)开头。   当正则表达式变为“”(^([a-z] +(?:\。[a-z] +)*)“”“。r,TestPattern(a)=> println(a)有效。

  6.