2017-12-12 10 views
0

変数に格納されている正規表現と、一致するパターン(以下に表示)に応じて文字列を返すマッチング操作があります。これらの変数をArrayまたはRegexのリストに変換したいので、インデックスを付けることができ、対応するグループを取得して適切な結果を返すことができます。パターンマッチングを使用した正規表現のスカラーリスト

既存のコード:

def parseString(str : String) : String = { 

    val ptrn2 = """/foo/bar/find/(apple|orange)/(\w+)$""".r 
    val ptrn3 = """/foo/bar/(fruit|vegetable)/(banana|carrot)/(\w+)$""".r 
    val ptrn4 = """/foo/bar/(volume|size)/(\d+)/(\d+)/(\d+)$""".r 
    // more variables 

    val response = str match { 
     case ptrn2(a,b) => "/foo/bar/"+ a +"/{id}" 
     case ptrn3(a,b,c) => "/foo/bar/"+ a +"/" + b + "/{ref}" 
     case ptrn4(a,b,c,d) => "/foo/bar/"+ a +"/" + (b.toInt*c.toInt*d.toInt) 
     // more case statements 
     case _ => str 
    } 
    return response 
} 

私はグループを取得するための変数を渡して、特定のインデックスにアクセスするには、以下の構文を使用しようとしましたが、これは正しくありません。それのどこが悪いんだい?

val prtn : List[Regex] = List(new Regex("regex here"), 
    new Regex("regex2 here"), 
    new Regex("regex3 here")) 

val response = str match { 
     case ptrn(0)(a,b) => "/foo/bar/"+ a +"/{id}" 
     case ptrn(1)(a,b,c) => "/foo/bar/"+ a +"/" + b + "/{ref}" 
     case ptrn(2)(a,b,c,d) => "/foo/bar/"+ a +"/" + (b.toInt*c.toInt*d.toInt) 
     case _ => str 
} 

マッチブロック内のArrays/Listを介してこれにアクセスする方法が必要です。マップが適切な結果を返した場合はさらに良いでしょう。誰もがScalaでこれを解決する方法を知っていますか?

答えて

0

私は今すぐテストする時間がありませんので、誰かがあなたにもっと正確な答えを与えるでしょう。しかし、これはスカラーがリストとのパターンマッチングを行う方法に関連していると思います。通常はunapplyに、ptrn(0)にはapplyとなります。試してみてください:

val response = str match { 
    case p(a,b) if p == ptrn(0) => "/foo/bar/"+ a +"/{id}" 
    case p(a,b,c) if p == ptrn(1) => "/foo/bar/"+ a +"/" + b + "/{ref}" 
    case p(a,b,c,d) if p == ptrn(2) => "/foo/bar/"+ a +"/" + (b.toInt*c.toInt*d.toInt) 
    case _ => str 
} 
+0

p'が解決できない 'ので、これは、コンパイルされないでしょう。抽出子と共に使用するには、 'p'は「安定した識別子」(例えば、値への参照)でなければなりません。 –

1

Scalaのパターンマッチングは、安定識別子(定義hereを参照)であると一致した発現を必要とします。正規表現が変数である最初のケースでは、各パターンは安定した識別子です。しかし、リストの要素はそうではありません。

パターンマッチングでこれを達成できるとは思わないが、unapplyを含まないRegexのAPIに頼らざるを得ません。また、正規表現だけでなく、の処理を行うリストを作成することで、冗長性を軽減することもできます。それぞれに冗長性を持たせることができます。

ここに1つの潜在的な実装です:

// instead of a simple list of regular expressions, make this a list of Tuples of (regex, builder), 
// where the builder is a function from the matched groups (List[String]) to the desired result (String) 
val ptrn = List(
    (
    """/foo/bar/find/(apple|orange)/(\w+)$""".r, 
    (groups: List[String]) => s"/foo/bar/${groups.head}/{id}" 
), 
    (
    """/foo/bar/(fruit|vegetable)/(banana|carrot)/(\w+)$""".r, 
    (groups: List[String]) => s"/foo/bar/${groups.head}/${groups(1)}/{ref}" 
), 
    (
    """/foo/bar/(volume|size)/(\d+)/(\d+)/(\d+)$""".r, 
    (groups: List[String]) => s"/foo/bar/${groups.head}/${groups(1).toInt * groups(2).toInt * groups(3).toInt})" 
) 
) 

// for some input: 
val str = "/foo/bar/fruit/banana/split" 

// First, flatMap to tuples of (Regex.Match, builder) - 
// the flatMap will "filter out" the ons that didn't match because None results would be lost 
val res = ptrn.flatMap { 
    case (reg, builder) => reg.findFirstMatchIn(str).map(m => (m, builder)) 
}.headOption.map { // then, take the first match and apply the builders to the matched groups 
    case (m, builder) => builder.apply(m.subgroups) 
}.getOrElse(str) // if no match found, use the original String 

println(res) // prints /foo/bar/fruit/banana/{ref} 
関連する問題