Scala正規表現:一致を配列またはリストとして返す方法

regex scala
Scala正規表現:一致を配列またはリストとして返す方法

正規表現の一致を配列として返す簡単な方法はありますか? + `2.7.7`で私がしようとしている方法は次のとおりです。

val s = """6 1 2"""
val re = """(\d+)\s(\d+)\s(\d+)""".r
for (m <- re.findAllIn (s)) println (m) // prints "6 1 2"
re.findAllIn (s).toList.length // 3? No! It returns 1!

しかし、私は次に試しました:

s match {
  case re (m1, m2, m3) => println (m1)
}

そしてこれはうまくいきます! m1は6、m2は1などです。

それから私は混乱に追加した何かを見つけました:

val mit = re.findAllIn (s)
println (mit.toString)
println (mit.length)
println (mit.toString)

それは印刷されます:

non-empty iterator
1
empty iterator

「長さ」呼び出しは、何らかの方法でイテレーターの状態を変更します。 ここで何が起こっているの?

  12  6


ベストアンサー

まず、 findAllIn`が Iterator`を返すことを理解してください。 「イテレータ」は、1回限りの変更可能なオブジェクトです。 あなたがそれに対してすることは何でもそれを変えるでしょう。 イテレータに慣れていない場合は、イテレータを読んでください。 再利用可能にしたい場合は、findAllInの結果を `List`に変換し、そのリストのみを使用します。

これで、すべての一致ではなく、すべての一致する_groups_が必要なようです。 メソッド `findAllIn`は、文字列で見つけることができる_full_正規表現のすべての一致を返します。 例えば:

scala> val s = """6 1 2, 4 1 3"""
s: java.lang.String = 6 1 2, 4 1 3

scala> val re = """(\d+)\s(\d+)\s(\d+)""".r
re: scala.util.matching.Regex = (\d+)\s(\d+)\s(\d+)

scala> for(m <- re.findAllIn(s)) println(m)
6 1 2
4 1 3

2つの一致があり、いずれも一致の一部ではないため、文字列の中央に「、」が含まれていないことを確認してください。

グループが必要な場合は、次のように取得できます。

scala> val s = """6 1 2"""
s: java.lang.String = 6 1 2

scala> re.findFirstMatchIn(s)
res4: Option[scala.util.matching.Regex.Match] = Some(6 1 2)

scala> res4.get.subgroups
res5: List[String] = List(6, 1, 2)

または、次のように `findAllIn`を使用します。

scala> val s = """6 1 2"""
s: java.lang.String = 6 1 2

scala> for(m <- re.findAllIn(s).matchData; e <- m.subgroups) println(e)
6
1
2

matchData`メソッドは、 String`の代わりに Match`を返す Iterator`を作成します。

25


unapplySeqが複数のグループを解釈する方法とfindAllInが行う方法には違いがあります。 findAllInは、文字列でパターンをスキャンし、一致する各文字列を返します(成功した場合は一致分、失敗した場合は1文字分進みます)。

だから、例えば:

scala> val s = "gecko 6 1 2 3 4 5"
scala> re.findAllIn(s).toList
res3: List[String] = List(6 1 2, 3 4 5)

一方、unapplySeqは、シーケンスに対する_perfect_一致を前提としています。

scala> re.unapplySeq(s)
res4: Option[List[String]] = None

したがって、正確な正規表現文字列で指定したグループを個別に解析する場合は、una​​pplySeqを使用します。 正規表現パターンのように見える文字列のサブセットを検索する場合は、findAllInを使用します。 両方を実行したい場合は、自分でチェーンします。

scala> re.findAllIn(s).flatMap(text => re.unapplySeq(text).elements )
res5: List[List[String]] = List(List(6, 1, 2), List(3, 4, 5))

9


これを試して:

  val s = """6 1 2"""
  val re = """\d+""".r
  println(re.findAllIn(s).toList) // List(6, 1, 2)
  println(re.findAllIn(s).toList.length) // 3

また、単一の正規表現内の一致グループのリストが本当に必要な場合:

  val s = """6 1 2"""
  val Re = """(\d+)\s(\d+)\s(\d+)""".r
  s match {  // this is just sugar for calling Re.unapplySeq(s)
      case Re([email protected]_*) => println(mg) // List(6, 1, 2)
  }

2


タイトルとURLをコピーしました