我有一些存储在变量中的正则表达式和一个匹配操作,它根据匹配的模式返回一个字符串(如下所示)。我想将这些变量转换为数组或正则表达式列表,因此可以将它们编入索引,然后我可以获得相应的组并返回相应的结果。
现有代码:
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访问它,或者如果Map返回了适当的结果会更好。有没有人知道如何在Scala中解决这个问题?
答案 0 :(得分:1)
Scala的模式匹配要求匹配的表达式为稳定标识符(请参阅定义here)。在第一种情况下,正则表达式是变量,每个模式都是稳定的标识符。但是列表中的元素不是。
我认为您无法使用模式匹配实现此目标,您必须使用Regex
不涉及unapply
的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}
答案 1 :(得分:0)
我现在没有时间进行测试,所以也许有人会给你一个更准确的答案。但我认为这与scala与列表进行模式匹配的方式有关:通常它与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
}