
.13.e.source-code.glob.scala Maven / Gradle / Ivy
/*
Copyright 2010 Aaron J. Radke
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cc.drx
object Glob{
/**smart vim/magic like constructor to not ignore the case if an upper case character exists in the pattern*/
def apply(glob:String):Glob = new Glob(glob, !glob.exists{c => c >= 'A' && c <= 'Z'})
def ignoreCase(glob:String):Glob = new Glob(glob, true)
def matchCase(glob:String):Glob = new Glob(glob, false)
//def apply(glob:String,ignoreCase:Boolean):Glob = new Glob(glob,ignoreCase)
implicit object ParsableGlob extends Parsable[Glob]{ def apply(glob:String):Glob = Glob(glob) }
final class GlobStringContext(val sc:StringContext) extends AnyVal{
def glob(args:Any*):Glob = Glob(sc.s(args:_*))
}
}
/**Glob version of a regex where * zero or more char and ? is any single character
* see https://en.wikipedia.org/wiki/Glob_(programming)
*/
class Glob(val glob: String, useIgnoreCase:Boolean, starPat:String="""[^\\/]"""){
override def toString = "Glob." + (if(useIgnoreCase) "ignoreCase" else "matchCase") + "(" + glob + ")"
def ignoreCase:Glob = new Glob(glob, true)
def matchCase:Glob = new Glob(glob, false)
//--List of characters that need to be escaped in regex https://stackoverflow.com/a/26228852/622016
lazy val regex:scala.util.matching.Regex = {
val pat = glob
.trim
.replaceAllLiterally("\\*","@LiteralStar")
.replaceAllLiterally("\\?","@LiteralQuestion")
.replaceAllLiterally("\\\\","@LiteralBackslash")
.replaceAllLiterally("**","@DoubleStar")
.replaceAllLiterally("*","@SingleStar")
.replaceAllLiterally("\\","\\\\") //literal slash
.replaceAllLiterally(".","\\.") //literal dot
.replaceAllLiterally("-","\\-") //stop the - character
.replaceAllLiterally("?","(.?)") //zero or one
.replaceAllLiterally("@LiteralStar","\\*")
.replaceAllLiterally("@LiteralQuestion","\\?")
.replaceAllLiterally("@LiteralBackslash","\\")
.replaceAllLiterally("@SingleStar",s"($starPat*)") //match zero or more equivocally
.replaceAllLiterally("@DoubleStar","(.*)") //match zero or more (unequivocally)
val flags = if(useIgnoreCase) "(?i)" else ""
("^" + flags + pat + "$").r //use ^ and $ to anchor the match to the full string
}
def matches(str:String):Boolean = find(str).isDefined
def doesNotMatch(str:String):Boolean = !matches(str)
def find(str:String) = regex findFirstMatchIn str
def subgroups(str:String):Option[List[String]] = regex.findFirstMatchIn(str).map{_.subgroups}
//retrieve subgroups of a match
def unapplySeq(str:String):Option[List[String]] = subgroups(str)
// def unapply(str:String):Option[String] = if(matches(str)) Some(str) else None //conflicts with unnaplySeq
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy