Scala convert a string to raw - regex

I know raw String can be declared as:
val foo: String = """foo"""
or
val foo: String = raw"foo"
However, if I have a string type val, how can I convert it to raw? For example:
// val toBeMatched = "line1: foobarfoo\nline2: lol"
def regexFoo(toBeMatched: String) = {
val pattern = "^.*foo[\\w+]foo.*$".r
val pattern(res) = toBeMatched /* <-- this line induces an exception
since Scala translates '\n' in string 'toBeMatched'. I want to convert
toBeMatched to raw string before pattern matching */
}

In your simple case, you can do this:
val a = "this\nthat"
a.replace("\n", "\\n") // this\nthat
For a more general solution, use StringEscapeUtils.escapeJava in Apache commons.
import org.apache.commons.lang3.StringEscapeUtils
StringEscapeUtils.escapeJava("this\nthat") // this\nthat
Note: your code doesn't actually make any sense. Aside from the fact that String toBeMatched is invalid Scala syntax, your regex pattern is set up such that it will only match the string "foo", not "foo\n" or "foo\\n", and pattern(res) only makes sense if your regex is attempting to capture something, which it's not.
Maybe (?!) you meant something like this?:
def regexFoo(toBeMatched: String) = {
val pattern = """foo(.*)""".r
val pattern(res) = toBeMatched.replace("\n", "\\n")
}
regexFoo("foo\n") // "\\n"

Related

How to use regex to find a keyword in Kotlin

fun main () {
val keyWords = listOf<String>("plus", "minus",
"divided by", "multiplied by", "what is")
val userInput : String? = readLine()
val rx = Regex( "\\W${keyWords.joinToString(separator = "|")}")
val result = keyWords
if (rx.matches(userInput)){
print("True")
}
}
I keep on getting the error of type mismatch and that it requires a Char sequence. I've tried different methods but I still haven't been able to find a solution.
Help me obi wan Kenobi you're my only hope
There are several issues that needs to be addressed:
Since userInput is nullable, you should make sure you do not pass a null value to regex engine that only expects CharSequence
The .matches() method requires a full string match, your regex only matches a part of a string, so you need to use Regex#containsMatchIn
The \W at the start of your pattern only requires a non-word char before the first alternative. It won't allow a match at the start of the string either. You need to use to wrap your alternatives with \b(?:...)\b.
Fixed Kotlin snippet:
if (userInput != null) {
val rx = Regex( "\\b(?:${keyWords.joinToString(separator = "|")})\\b")
print (rx.containsMatchIn(userInput))
}
If your keyWords can contain special characters you will need to escape special characters and then use either unambiguous word boundaries
val rx = Regex( "(?<!\\w)(?:${keyWords.map{Regex.escape(it)}.joinToString("|")})(?!\\w)")
or whitespace boundaries:
val rx = Regex( "(?<!\\S)(?:${keyWords.map{Regex.escape(it)}.joinToString("|")})(?!\\S)")
The issue is that userInput is nullable.
10:20: error: type mismatch: inferred type is String? but CharSequence was expected
if (rx.matches(userInput)){
String implements CharSequence.
One way to solve that would be to check for null:
val userInput : String? = readLine()
if (userInput != null) {
val rx = Regex( "\\W${keyWords.joinToString(separator = "|")}")
val result = keyWords
if (rx.matches(userInput)){
print("True")
}
}

How to use match with regular expressions in Scala

I am starting to learn Scala and want to use regular expressions to match a character from a string so I can populate a mutable map of characters and their value (String values, numbers etc) and then print the result.
I have looked at several answers on SO and gone over the Scala Docs but can't seem to get this right. I have a short Lexer class that currently looks like this:
class Lexer {
private val tokens: mutable.Map[String, Any] = collection.mutable.Map()
private def checkCharacter(char: Character): Unit = {
val Operator = "[-+*/^%=()]".r
val Digit = "[\\d]".r
val Other = "[^\\d][^-+*/^%=()]".r
char.toString match {
case Operator(c) => tokens(c) = "Operator"
case Digit(c) => tokens(c) = Integer.parseInt(c)
case Other(c) => tokens(c) = "Other" // Temp value, write function for this
}
}
def lex(input: String): Unit = {
val inputArray = input.toArray
for (s <- inputArray)
checkCharacter(s)
for((key, value) <- tokens)
println(key + ": " + value)
}
}
I'm pretty confused by the sort of strange method syntax, Operator(c), that I have seen being used to handle the value to match and am also unsure if this is the correct way to use regex in Scala. I think what I want this code to do is clear, I'd really appreciate some help understanding this. If more info is needed I will supply what I can
This official doc has lot's of examples: https://www.scala-lang.org/api/2.12.1/scala/util/matching/Regex.html. What might be confusing is the type of the regular expression and its use in pattern matching...
You can construct a regex from any string by using .r:
scala> val regex = "(something)".r
regex: scala.util.matching.Regex = (something)
Your regex becomes an object that has a few useful methods to be able to find matching groups like findAllIn.
In Scala it's idiomatic to use pattern matching for safe extraction of values, thus Regex class also has unapplySeq method to support pattern matching. This makes it an extractor object. You can use it directly (not common):
scala> regex.unapplySeq("something")
res1: Option[List[String]] = Some(List(something))
or you can let Scala compiler call it for you when you do pattern matching:
scala> "something" match {
| case regex(x) => x
| case _ => ???
| }
res2: String = something
You might ask why exactly this return type on unapply/unapplySeq. The doc explains it very well:
The return type of an unapply should be chosen as follows:
If it is just a test, return a Boolean. For instance case even().
If it returns a single sub-value of type T, return an Option[T].
If you want to return several sub-values T1,...,Tn, group them in an optional tuple Option[(T1,...,Tn)].
Sometimes, the number of values to extract isn’t fixed and we would
like to return an arbitrary number of values, depending on the input.
For this use case, you can define extractors with an unapplySeq method
which returns an Option[Seq[T]]. Common examples of these patterns
include deconstructing a List using case List(x, y, z) => and
decomposing a String using a regular expression Regex, such as case
r(name, remainingFields # _*) =>
In short your regex might match one or more groups, thus you need to return a list/seq. It has to be wrapped in an Option to comply with extractor contract.
The way you are using regex is correct, I would just map your function over the input array to avoid creating mutable maps. Perhaps something like this:
class Lexer {
private def getCharacterType(char: Character): Any = {
val Operator = "([-+*/^%=()])".r
val Digit = "([\\d])".r
//val Other = "[^\\d][^-+*/^%=()]".r
char.toString match {
case Operator(c) => "Operator"
case Digit(c) => Integer.parseInt(c)
case _ => "Other" // Temp value, write function for this
}
}
def lex(input: String): Unit = {
val inputArray = input.toArray
val tokens = inputArray.map(x => x -> getCharacterType(x))
for((key, value) <- tokens)
println(key + ": " + value)
}
}
scala> val l = new Lexer()
l: Lexer = Lexer#60f662bd
scala> l.lex("a-1")
a: Other
-: Operator
1: 1

Cannot retrive a group from Scala Regex match

I am struggling with regexps in Scala (2.11.5), I have a followin string to parse (example):
val string = "http://sth.com/sth/56,57597,14058913,Article_title,,5.html"
I want to extract third numeric value in the string above (it needs to be third after a slash because there can be other groups following), in order to do that I have the following regex pattern:
val pattern = """\/\d+,\d+,(\d+)""".r
I have been trying to retrieve the group for the third sequence of digits, but nothing seems to work for me.
val matchList = pattern.findAllMatchIn(string).foreach(println)
val matchListb = pattern.findAllIn(string).foreach(println)
I also tried using matching pattern.
string match {
case pattern(a) => println(a)
case _ => "What's going on?"
}
and got the same results. Either whole regexp is returned or nothing.
Is there an easy way to retrieve a group form regexp pattern in Scala?
You can use group method of scala.util.matching.Regex.Match to get the result.
val string = "http://sth.com/sth/56,57597,14058913,Article_title,,5.html"
val pattern = """\/\d+,\d+,(\d+)""".r
val result = pattern.findAllMatchIn(string) // returns iterator of Match
.toArray
.headOption // returns None if match fails
.map(_.group(1)) // select first regex group
// or simply
val result = pattern.findFirstMatchIn(string).map(_.group(1))
// result = Some(14058913)
// result will be None if the string does not match the pattern.
// if you have more than one groups, for instance:
// val pattern = """\/(\d+),\d+,(\d+)""".r
// result will be Some(56)
Pattern matching is usually the easiest way to do it, but it requires a match on the full string, so you'll have to prefix and suffix your regex pattern with .*:
val string = "http://sth.com/sth/56,57597,14058913,Article_title,,5.html"
val pattern = """.*\/\d+,\d+,(\d+).*""".r
val pattern(x) = string
// x: String = 14058913

Splitting string using Regex and pattern matching throws an exception

Could you guys please tell me what I'm doing incorrectly trying to extract using regex pattern-matching? I have following code
val Pattern = "=".r
val Pattern(key, value) = "key=value"
And I get following exception in runtime
Exception in thread "main" scala.MatchError: key=value (of class java.lang.String)
That's more of a regular expression problem: your regex does not capture any groups, it just matches a single = character.
With
val Pattern = "([^=]*)=(.*)".r
you will get:
scala> val Pattern(key, value) = "key=value"
key: String = key
value: String = value
Edit:
Also, that won't match if the input string is empty. You can change the pattern to make it match, or (better) you can pattern match with the regex, like so:
"key=value" match {
case Pattern(k, v) => // do something
case _ => // wrong input, do nothing
}
If what you actually wanted was to split the input text with whatever the regex matches, that is also possible using Regex.split:
scala> val Pattern = "=".r
Pattern: scala.util.matching.Regex = =
scala> val Array(key, value) = Pattern.split("key=value")
key: String = key
value: String = value

Scala capture group using regex

Let's say I have this code:
val string = "one493two483three"
val pattern = """two(\d+)three""".r
pattern.findAllIn(string).foreach(println)
I expected findAllIn to only return 483, but instead, it returned two483three. I know I could use unapply to extract only that part, but I'd have to have a pattern for the entire string, something like:
val pattern = """one.*two(\d+)three""".r
val pattern(aMatch) = string
println(aMatch) // prints 483
Is there another way of achieving this, without using the classes from java.util directly, and without using unapply?
Here's an example of how you can access group(1) of each match:
val string = "one493two483three"
val pattern = """two(\d+)three""".r
pattern.findAllIn(string).matchData foreach {
m => println(m.group(1))
}
This prints "483" (as seen on ideone.com).
The lookaround option
Depending on the complexity of the pattern, you can also use lookarounds to only match the portion you want. It'll look something like this:
val string = "one493two483three"
val pattern = """(?<=two)\d+(?=three)""".r
pattern.findAllIn(string).foreach(println)
The above also prints "483" (as seen on ideone.com).
References
regular-expressions.info/Lookarounds
val string = "one493two483three"
val pattern = """.*two(\d+)three.*""".r
string match {
case pattern(a483) => println(a483) //matched group(1) assigned to variable a483
case _ => // no match
}
Starting Scala 2.13, as an alternative to regex solutions, it's also possible to pattern match a String by unapplying a string interpolator:
"one493two483three" match { case s"${x}two${y}three" => y }
// String = "483"
Or even:
val s"${x}two${y}three" = "one493two483three"
// x: String = one493
// y: String = 483
If you expect non matching input, you can add a default pattern guard:
"one493deux483three" match {
case s"${x}two${y}three" => y
case _ => "no match"
}
// String = "no match"
You want to look at group(1), you're currently looking at group(0), which is "the entire matched string".
See this regex tutorial.
def extractFileNameFromHttpFilePathExpression(expr: String) = {
//define regex
val regex = "http4.*\\/(\\w+.(xlsx|xls|zip))$".r
// findFirstMatchIn/findAllMatchIn returns Option[Match] and Match has methods to access capture groups.
regex.findFirstMatchIn(expr) match {
case Some(i) => i.group(1)
case None => "regex_error"
}
}
extractFileNameFromHttpFilePathExpression(
"http4://testing.bbmkl.com/document/sth1234.zip")