Reputation: 1969
From this answer to a related Scala Regex Partial Function question, I am able to define a partial function which matches a regex pattern using the following code:
val regex = "(\\d+),([A-z]+)".r
val input = List("1,a", "23,zZ", "1", "1ab", "")
scala> input collect { case regex(a, b) => (a, b) }
res2: List[(String, String)] = List((1,a), (23,zZ))
The first line defines the regex while the second line defines the input. Is it possible that I move the definition of the regex to be inside the partial function? I have tried doing:
scala> input collect { val regex = "(\\d+),([A-z]+)".r; case regex(a, b) => (a, b) }
But the code will not compile. Is it possible to define the regex to be matched inside the function (or at least scope enclosed)?
The input is a list of strings. Each string would match a different regex and would be handled differently. For example, if the string is a number-alphabets pair, return the number; if the string is a date in ISO format, return the year; if the string is an uppercase string, return the last 4 characters.
Input: List("1,a", "23,zZ", "1990-10-21", "1ab", "", "ABCDEF")
Output: List("1", "23", "1990", "CDEF")
The number of cases and the cases themselves could change, so the code should be able to handle those changes.
Upvotes: 0
Views: 288
Reputation: 106
import scala.util.matching.Regex
trait RegexRule {
val rule: Regex
def apply(): PartialFunction[String, String] = {
case rule(a, _*) => a
}
}
object RegexRule {
def createMatcher(l: Seq[RegexRule]): PartialFunction[String, String] =
l.map(_.apply()).reduce(_.orElse(_))
}
object DateRegexRule extends RegexRule {
val rule: Regex = "(\\d{4})-(\\d{2})-(\\d{2})".r
}
object NumberRegexRule extends RegexRule {
val rule: Regex = "(\\d+),([A-z]+)".r
}
object AlphabeticRegexRule extends RegexRule {
val rule: Regex = "([A-Z]+)".r
override def apply(): PartialFunction[String, String] =
super.apply().andThen(_.takeRight(4))
}
object PartialFunctionWithRegex extends App {
val input = List("1,a", "23,zZ", "1991-12-31", "1ab", "", "ABCEDT")
val regexRules: Seq[RegexRule] =
Seq(DateRegexRule, NumberRegexRule, AlphabeticRegexRule)
val matchers: PartialFunction[String, String] =
RegexRule.createMatcher(regexRules)
val result = input.collect(matchers)
println(result)
//List(1, 23, 1991, CEDT)
}
just you need to implement new instance of RegexRule for each kind of regex.
Upvotes: 0
Reputation: 1969
I was able to define the regex in an enclosed scope that returns the partial function:
{ val regex = "(\\d+),([A-z]+)".r; { case regex(a, _*) => a } }
The partial function can be used as:
val input = List("1,a", "23,zZ", "1991-12-31", "1ab", "")
val matchers: List[PartialFunction[String, String]] = List(
{ val regex = "(\\d{4})-(\\d{2})-(\\d{2})".r; { case regex(a, _*) => a } },
{ val regex = "(\\d+),([A-z]+)".r; { case regex(a, _*) => a } },
{ val regex = "([A-Z]+)".r; { case regex(a) => a takeRight 4 } },
)
Upvotes: 1