A regular expression is used to determine whether a string matches a pattern and, if it does, to extract or transform the parts that match.
A regular expression is used to determine whether a string matches a pattern and, if it does, to extract or transform the parts that match.
This class delegates to thejava.util.regex package of the Java Platform. See the documentation forjava.util.regex.Pattern for details about the regular expression syntax for pattern strings.
An instance ofRegex represents a compiled regular expression pattern. Since compilation is expensive, frequently usedRegexes should be constructed once, outside of loops and perhaps in a companion object.
The canonical way to create aRegex is by using the methodr, provided implicitly for strings:
val date = raw"(\d{4})-(\d{2})-(\d{2})".rSince escapes are not processed in multi-line string literals, using triple quotes avoids having to escape the backslash character, so that"\\d" can be written"""\d""". The same result is achieved with certain interpolators, such asraw"\d".r or a custom interpolatorr"\d" that also compiles theRegex.
To extract the capturing groups when aRegex is matched, use it as an extractor in a pattern match:
"2004-01-20" match { case date(year, month, day) => s"$year was a good year for PLs."}To check only whether theRegex matches, ignoring any groups, use a sequence wildcard:
"2004-01-20" match { case date(_*) => "It's a date!"}That works because aRegex extractor produces a sequence of strings. Extracting only the year from a date could also be expressed with a sequence wildcard:
"2004-01-20" match { case date(year, _*) => s"$year was a good year for PLs."}In a pattern match,Regex normally matches the entire input. However, an unanchoredRegex finds the pattern anywhere in the input.
val embeddedDate = date.unanchored"Date: 2004-01-20 17:25:18 GMT (10 years, 28 weeks, 5 days, 17 hours and 51 minutes ago)" match { case embeddedDate("2004", "01", "20") => "A Scala is born."}To find or replace matches of the pattern, use the various find and replace methods. For each method, there is a version for working with matched strings and another for working withMatch objects.
For example, pattern matching with an unanchoredRegex, as in the previous example, can also be accomplished usingfindFirstMatchIn. ThefindFirst methods return anOption which is non-empty if a match is found, orNone for no match:
val dates = "Important dates in history: 2004-01-20, 1958-09-05, 2010-10-06, 2011-07-15"val firstDate = date.findFirstIn(dates).getOrElse("No date found.")val firstYear = for (m <- date.findFirstMatchIn(dates)) yield m.group(1)To find all matches:
val allYears = for (m <- date.findAllMatchIn(dates)) yield m.group(1)To check whether input is matched by the regex:
date.matches("2018-03-01") // truedate.matches("Today is 2018-03-01") // falsedate.unanchored.matches("Today is 2018-03-01") // trueTo iterate over the matched strings, usefindAllIn, which returns a special iterator that can be queried for theMatchData of the last match:
val mi = date.findAllIn(dates)while (mi.hasNext) { val d = mi.next if (mi.group(1).toInt < 1960) println(s"$d: An oldie but goodie.")}Although theMatchIterator returned byfindAllIn is used like anyIterator, with alternating calls tohasNext andnext,hasNext has the additional side effect of advancing the underlying matcher to the next unconsumed match. This effect is visible in theMatchData representing the "current match".
val r = "(ab+c)".rval s = "xxxabcyyyabbczzz"r.findAllIn(s).start // 3val mi = r.findAllIn(s)mi.hasNext // truemi.start // 3mi.next() // "abc"mi.start // 3mi.hasNext // truemi.start // 9mi.next() // "abbc"The example shows that methods onMatchData such asstart will advance to the first match, if necessary. It also shows thathasNext will advance to the next unconsumed match, ifnext has already returned the current match.
The currentMatchData can be captured using thematchData method. Alternatively,findAllMatchIn returns anIterator[Match], where there is no interaction between the iterator andMatch objects it has already produced.
Note thatfindAllIn finds matches that don't overlap. (SeefindAllIn for more examples.)
val num = raw"(\d+)".rval all = num.findAllIn("123").toList // List("123"), not List("123", "23", "3")Text replacement can be performed unconditionally or as a function of the current match:
val redacted = date.replaceAllIn(dates, "XXXX-XX-XX")val yearsOnly = date.replaceAllIn(dates, m => m.group(1))val months = (0 to 11).map { i => val c = Calendar.getInstance; c.set(2014, i, 1); f"$c%tb" }val reformatted = date.replaceAllIn(dates, _ match { case date(y,m,d) => f"${months(m.toInt - 1)} $d, $y" })Pattern matching theMatch against theRegex that created it does not reapply theRegex. In the expression forreformatted, eachdate match is computed once. But it is possible to apply aRegex to aMatch resulting from a different pattern:
val docSpree = """2011(?:-\d{2}){2}""".rval docView = date.replaceAllIn(dates, _ match { case docSpree() => "Historic doc spree!" case _ => "Something else happened"})A mapping from names to indices in capture groups
The compiled pattern
This object defines inner classes that describe regex matches and helper objects.
This object defines inner classes that describe regex matches and helper objects.
ARegex that finds the first match when used in a pattern match.
ARegex that finds the first match when used in a pattern match.