Scala正则表达式模式匹配无法运行

3
我正在尝试编写一个用于匹配由句点分隔的字符串的正则表达式。例如,
"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个回答

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

就像其他答案中所示,如果一个组匹配了多次,你总是会得到最后一次匹配的结果。这是底层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

最后一个表达式检查数组parts中的所有元素是否都与正则表达式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)

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


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. "case TestPattern(a)"不起作用,因为参数的数量必须与捕获组的数量相同。
    每个开括号都会开始一个新的捕获组。 例如:"""^([a-z]+(\.[a-z]+))""".r有2个捕获组,"""^(([a-z]+(\.[a-z]+)))""".r有3个。 所以后者将与TestPattern(a, b, c)匹配。
  3. 由于在这种情况下第二个捕获组是不必要的,我们可以使用非捕获组,它以(?:开头而不是(。
    当正则表达式更改为"""^([a-z]+(?:\.[a-z]+)*)""".r时,TestPattern(a) => println(a)就可以工作了。

单个反斜杠和双个反斜杠有什么区别?另外,“case TestPattern(a) => println(a)”为什么不起作用呢?整个模式不是只有一个组件吗? - vikky.rk

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