繁体   English   中英

具有模式匹配的正则表达式的Scala列表

[英]Scala list of regular expressions with pattern matching

我有一些存储在变量中的正则表达式以及一个匹配操作,该操作根据匹配的模式返回一个字符串(如下所示)。 我想将这些变量转换为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
 }

必须有一种方法可以通过match块中的Arrays / List来访问它,否则,如果Map返回适当的结果,那就更好了。 有谁知道如何在Scala中解决此问题?

Scala的模式匹配要求匹配的表达式必须是稳定的标识符 (请参见此处的定义)。 在第一种情况下,正则表达式是一个变量,每个模式都是一个稳定的标识符。 但是列表中的元素不是。

我认为您无法通过模式匹配来实现这一点,您必须诉诸不涉及unapply Regex API。 此外,您就可以通过创建不仅包含了正则表达式的列表,以减少冗长,还能有什么与他们每个人做的

这是一个潜在的实现:

// 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} 

我现在没有时间进行测试,因此也许有人会给您一个更准确的答案。 但我认为这是关系到斯卡拉的方式将做图案列表匹配:通常是涉及到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
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM