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

これには2つのコンポーネントがあり、

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. この場合、2 番目のキャプチャ グループは必要ないため、(の代わりに (?: で始まる非キャプチャ グループを使用できます。
    正規表現が """^([az]+(?: \.[az]+)*)""".r, TestPattern(a) => println(a) が動作します。

于 2013-08-05T08:22:57.833 に答える