Last active
February 27, 2016 19:16
-
-
Save kostrse/0429a6aeee4414e66b97 to your computer and use it in GitHub Desktop.
Wildcard search on Scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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