Skip to content

Instantly share code, notes, and snippets.

@Aivean
Created September 10, 2016 20:26
Show Gist options
  • Save Aivean/6b2bb7c2473b4b7e1376fac1d2d49cf8 to your computer and use it in GitHub Desktop.
Save Aivean/6b2bb7c2473b4b7e1376fac1d2d49cf8 to your computer and use it in GitHub Desktop.
Glob matcher implementation in Scala
case class State(matches: String => Boolean, optional: Boolean)
def matcher(pattern: String): String => Boolean = {
val states = pattern.split("/").toList.map {
case "**" => State(_ => true, true)
case s =>
val r = s.replaceAllLiterally("*", ".*").r
State(r.unapplySeq(_).isDefined, false)
}.zipWithIndex
/**
* cur[idx] means whether position _before_ rest of the path
* can be reached using the pattern _before_ state idx
*/
def rec(path: List[String], cur: Set[Int]): Boolean = path match {
case Nil => states.drop((cur + 0).max).forall(_._1.optional)
case h :: t =>
def srec(sts: List[(State, Int)], cur: Set[Int], next: Set[Int]): Set[Int] =
sts match {
case Nil => next
case (_, i) :: t if !cur(i) => srec(t, cur, next)
case (s, i) :: t =>
if (s.optional) srec(t, cur + (i + 1), (next + i) + (i + 1))
else srec(t, cur, if (s.matches(h)) next + (i + 1) else next)
}
rec(t, srec(states, cur, Set.empty))
}
path => rec(path.split("/").toList, Set(0))
}
val m = matcher("**/b/c")
m("b/c/b/c")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment