Scala Regular Expressions
Scala Regular Expressions
Section titled “Scala Regular Expressions”Scala provides built-in support for regular expressions via the scala.util.matching.Regex class. The most idiomatic way to create a Regex instance is by calling the .r method on a String.
Creating Regex Instances:
Section titled “Creating Regex Instances:”import scala.util.matching.Regex
// Using the .r method (preferred)val simplePattern: Regex = "Scala".rval digitPattern = "\\d+".r // Need double backslash for literal backslash in string
// Using the Regex constructorval caseInsensitivePattern = new Regex("(?i)scala") // (?i) flag for case-insensitivityFinding Matches:
Section titled “Finding Matches:”Several methods allow you to find matches within a target string.
findFirstIn(target): Returns an Option[String] containing the first match, or None if no match is found.
Section titled “findFirstIn(target): Returns an Option[String] containing the first match, or None if no match is found.”val text = "Scala is scalable and cool. scala rocks!"val pattern = "[Ss]cala".r // Match 'Scala' or 'scala'
val firstMatch = pattern.findFirstIn(text)println(s"First match: $firstMatch") // Output: First match: Some(Scala)findAllIn(target): Returns an Iterator[String] over all non-overlapping matches.
Section titled “findAllIn(target): Returns an Iterator[String] over all non-overlapping matches.”val allMatchesIterator = pattern.findAllIn(text)val allMatchesList = allMatchesIterator.toList // Convert iterator to List for easier use
println(s"All matches: $allMatchesList") // Output: All matches: List(Scala, scala)You can use .mkString to easily format the results from findAllIn:
println(s"All matches joined: ${pattern.findAllIn(text).mkString(", ")}") // Output: All matches joined: Scala, scalafindPrefixOf(target): Returns an Option[String] if the regex matches the beginning of the target string.
Section titled “findPrefixOf(target): Returns an Option[String] if the regex matches the beginning of the target string.”val startsWithScala = pattern.findPrefixOf(text)println(s"Starts with Scala?: $startsWithScala") // Output: Starts with Scala?: Some(Scala)
val otherText = "Cool Scala"println(s"Starts with Scala?: ${pattern.findPrefixOf(otherText)}") // Output: Starts with Scala?: NoneChecking for Matches:
Section titled “Checking for Matches:”matches(target): Returns Boolean indicating if the entire target string matches the regex.
Section titled “matches(target): Returns Boolean indicating if the entire target string matches the regex.”val numberPattern = "\\d{3}-\\d{4}".r // Matches XXX-XXXX formatval phone1 = "123-4567"val phone2 = "123-456"val phone3 = "abc-defg"
println(s"'$phone1' matches? ${numberPattern.matches(phone1)}") // Output: '123-4567' matches? trueprintln(s"'$phone2' matches? ${numberPattern.matches(phone2)}") // Output: '123-456' matches? falseprintln(s"'$phone3' matches? ${numberPattern.matches(phone3)}") // Output: 'abc-defg' matches? falseReplacing Text:
Section titled “Replacing Text:”replaceFirstIn(target, replacement): Replaces the first match.
Section titled “replaceFirstIn(target, replacement): Replaces the first match.”val replacedFirst = pattern.replaceFirstIn(text, "Java")println(s"Replace first: $replacedFirst")// Output: Replace first: Java is scalable and cool. scala rocks!replaceAllIn(target, replacement): Replaces all matches.
Section titled “replaceAllIn(target, replacement): Replaces all matches.”val replacedAll = pattern.replaceAllIn(text, "Python")println(s"Replace all: $replaceAll")// Output: Replace all: Python is scalable and cool. Python rocks!You can also use a function for the replacement, allowing dynamic replacements based on the match.
val dynamicReplace = pattern.replaceAllIn(text, m => s"[${m.matched.toUpperCase}]" )println(s"Dynamic replace: $dynamicReplace")// Output: Dynamic replace: [SCALA] is scalable and cool. [SCALA] rocks!Extracting Groups:
Section titled “Extracting Groups:”When a regex contains capturing groups (defined by parentheses ()), you can extract these captured parts.
val keyValuePattern = "(\w+)=(\d+)".r // Group 1: key (word), Group 2: value (digits)val data = "config=100, type=2, user=abc" // Note: 'user=abc' won't match \d+
println("\nExtracting key-value pairs:")for (keyValuePattern(key, value) <- keyValuePattern.findAllIn(data)) { println(s"Key: $key, Value: $value (as String)")}Output:
Extracting key-value pairs:Key: config, Value: 100 (as String)Key: type, Value: 2 (as String)This uses the Regex object as an extractor in a for comprehension or match statement. keyValuePattern(key, value) attempts to match the pattern and extract the groups into the key and value variables.
Regex Syntax Reference:
Section titled “Regex Syntax Reference:”Scala uses Java’s regular expression syntax, which is largely compatible with Perl.
Common Metacharacters & Constructs:
Section titled “Common Metacharacters & Constructs:”| Syntax | Description |
|---|---|
| . | Any single character (except newline unless DOTALL flag is set) |
| \d | A digit [0-9] |
| \D | A non-digit [^0-9] |
| \s | A whitespace character [ \t\n\x0B\f\r] |
| \S | A non-whitespace character |
| \w | A word character [a-zA-Z_0-9] |
| \W | A non-word character |
| ^ | Beginning of the line/string |
| $ | End of the line/string |
| \b | Word boundary |
| \B | Non-word boundary |
| [abc] | Character class: ‘a’, ‘b’, or ‘c’ |
| [^abc] | Negated class: any character except ‘a’, ‘b’, or ‘c’ |
| [a-z] | Range: any lowercase letter |
| a|b | Alternation: ‘a’ or ‘b’ |
| (…) | Capturing group |
| (?:…) | Non-capturing group |
| X? | Quantifier: Zero or one ‘X’ |
| X* | Quantifier: Zero or more ‘X’ |
| X+ | Quantifier: One or more ‘X’ |
| X{n} | Quantifier: Exactly ‘n’ occurrences of ‘X’ |
| X{n,} | Quantifier: ‘n’ or more occurrences of ‘X’ |
| X{n,m} | Quantifier: At least ‘n’ but not more than ‘m’ occurrences of ‘X’ |
Important: Remember to escape backslashes within Scala string literals. To match a literal backslash \, use \\ in the string. To match a digit \d, use "\\d".