Skip to content

Instantly share code, notes, and snippets.

@kostrse
Last active February 27, 2016 19:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kostrse/0429a6aeee4414e66b97 to your computer and use it in GitHub Desktop.
Save kostrse/0429a6aeee4414e66b97 to your computer and use it in GitHub Desktop.
Wildcard search on Scala
object Program {
val testText = "The quick brown fox jumps over a lazy dog."
val testPattern = "fox * over"
def main (args: Array[String]) {
println(
s"""
|Text: $testText
|Pattern: $testPattern
|
|Matches:""".stripMargin)
println(searchPattern(testText, testPattern) mkString "\n")
}
def searchPattern(text: String, pattern: String): List[String] = {
def isWildcard(patternChar: Char): Boolean = patternChar == '*'
def matchPatternAtOffset(textOffset: Int, patternOffset: Int): Option[Int] = {
if (patternOffset == pattern.length) {
// Successful match: we've reached end of the pattern.
Some(textOffset)
} else if (textOffset == text.length) {
// No match: we've reached end of the text
None
} else if (isWildcard(pattern(patternOffset))) {
// The current pattern character is a [0;∞) wildcard.
// This means we need to continue trying to match remaining of the pattern against
// all positions of the text beginning from the current offset till the last position in the text.
val submatches = (textOffset to text.length - 1).iterator map { x =>
matchPatternAtOffset(x, patternOffset + 1)
}
// Returning the first successful match as result (if any found)
submatches collectFirst { case Some(x) => x }
} else if (text(textOffset) == pattern(patternOffset)) {
// Current character matched: moving to one position ahead and continuing
matchPatternAtOffset(textOffset + 1, patternOffset + 1)
} else {
// Characters don't match
None
}
}
/**
* This method iterates through the text and tries to find matches.
* @param offset Starting offset in the text.
* @return List of found matches.
*/
def searchPatternAtOffset(offset: Int): List[String] = {
if (offset == text.length)
// We have reached end of the text, nothing can be found anymore
// Returning list terminator
return Nil
matchPatternAtOffset(offset, 0) match {
case Some(endOffset) =>
// We have a match at this offset, jumping to end of the match and concatenating results of
// this match with possible matches ahead in this text
text.substring(offset, endOffset) :: searchPatternAtOffset(endOffset)
case None =>
// Nothing found at this offset, trying one position ahead
searchPatternAtOffset(offset + 1)
}
}
// Starting actual search from beginning of the text (offset 0)
searchPatternAtOffset(0)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment