2017-12-12 4 views
0

일치하는 패턴 (아래 표시)에 따라 문자열을 반환하는 변수 및 일치 연산에 저장된 정규식이 있습니다. 이러한 변수를 Array 또는 Regex List로 변환하여 인덱싱 할 수 있으므로 해당 그룹을 가져 와서 적절한 결과를 반환 할 수 있습니다.패턴 일치가있는 정규식 스칼라 목록

기존 코드 :

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를 통해 액세스 할 수있는 방법이 있어야합니다.지도가 적절한 결과를 반환하면 더 좋을 것입니다. 누구든지 스칼라에서 이것을 해결하는 방법을 알고 있습니까?

답변

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'가 '안정된 식별자'(예 : 값 참조) 여야합니다. –

1

스칼라의 패턴 매칭은 안정적인 식별자 (정의 here 참조)로 일치하는 표현을 필요로한다. 첫 번째 경우 정규 표현식이 변수 인 경우 각 패턴은 안정적인 식별자입니다. 그러나 목록의 요소는 그렇지 않습니다.

패턴 매칭을 통해이를 달성 할 수 있다고 생각하지 않는다면, unapply이 포함되지 않은 Regex의 API를 사용해야 할 것입니다. 또한 정규 표현식을 포함 할뿐만 아니라 할 일을 목록으로 작성하여 자세한 정보를 줄일 수 있습니다. 각각을 사용하십시오. p`를 해결할 수없는`때문에,

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