2012年9月21日金曜日

[Scala] 正規表現によるマッチ

正規表現を使った match ... case 文を使ってみる。

val p : Regex = ".*no=([0-9]+),name=(.*)".r;
val values = List(
  "no=10,name=ten",
  "no=11,name=eleven",
  "no=20,name=twelve" );

for (value <- values ) {
  value match {
    case p("10", v) => println("name for 10: " + v)
    case p("11", v) => println("name for 11: " + v)
    case p(n, v) => println("name, value= " + (n,v))
  } 
}

name for 10: ten name for 11: eleven name, value= (20,twelve)

String#r メソッドで scala.util.matching.Regex オブジェクトを作ることができる。

match ... case 文の case 句で、正規表現中のグループに対する値や変数を指定しておくことで、 比較対象の文字列とマッチさせることができる。

上の例の最初と2つめの case 句では、第一グループに値を指定してマッチした対象の第2グループの値を変数に入れて取り出す。
3番目の case 句では1番目、2番目の case 句でマッチしなかった対象に対して両グループの値を取り出している。



この動作の仕組みを調べてみよう。
Scala の Regex は普通こんな感じで使う。

val p : Regex = """.*no=([0-9]+),name=(.*)""".r;
val s = "no=10,name=ten";

val m : Regex.Match = p.findFirstMatchIn(s).get;
println("no: " + m.group(1))
println("name: " + m.group(2))

no: 10 name: ten

Regex には メンバーメソッドに抽出子 unapplySeq があって文字列を渡すことができる。

val p : Regex = """.*no=([0-9]+),name=(.*)""".r;
val s = "no=10,name=ten";
println(p.unapplySeq(s));

Some(List(10, ten))

正規表現を使った match...case 文ではこの抽出子を使ってグループの値を取り出して マッチを行っているものと思う。

Regex の派生クラスを作って、unapplySeq を override して実験。

    val p : Regex = new Regex2(""".*no=([0-9]+),name=(.*)""");
    val value = "no=10,name=ten";
    value match {
      case p("10", v) => println("name for 10: " + v)
      case p(n, v) => println("name, value= " + (n,v))
     }
...
private class Regex2(regex: String) extends Regex(regex)  {
  override def unapplySeq(target: Any): Option[List[String]] = {
      println("Regex2 unapplySeq called.");
      return super.unapplySeq(target);
  }
}
Regex2 unapplySeq called. name for 10: ten

確かに Regex の unapplySeq が実行されていることが分かった。

0 件のコメント:

コメントを投稿