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

没有出现在我的输出中。

4

3 回答 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)
于 2013-08-05T07:23:16.013 回答
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)

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

于 2013-08-05T10:36:10.580 回答
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)”不起作用,因为参数的数量必须与捕获组的数量相同。
    每个开括号开始一个新的捕获组。例如 """^([az]+(\.[az]+) )""".r 有 2 个捕获组, """^(([az]+(\.[az]+) ) )""".r 有 3 个。所以后者将与 TestPattern(a, b, c) 匹配。

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

于 2013-08-05T08:22:57.833 回答