How to get multiple regex on same string in scala - regex

My requirement is to get multiple regex patterns in a given String.
"<a href=\"https://page1.google.com/ab-cd/ABCDEF\”>Hello</a> hiiii <a href=\"https://page2.yahoo.com/gr\”>page</a><img src=\"https://image01.google.com/gr/content/attachment/987654321\” alt=\”demo image\”></a><a href=\"https://page3.google.com/hr\">"
With this below code:
val p = Pattern.compile("href=\"(.*?)\"")
val m = p.matcher(str)
while(m.find()){
println(m.group(1))
}
I am getting output:
https://page1.google.com/ab-cd/ABCDEF
https://page2.yahoo.com/gr
https://page3.google.com/hr
With change in Pattern:
val p = Pattern.compile("img src=\"(.*?)\"")
I am getting output:
https://image01.google.com/gr/content/attachment/987654321
But with Pattern:
val p = Pattern.compile("href=\"(.*?)\"|img src=\"(.*?)\"")
I am getting output:
https://page1.google.com/ab-cd/ABCDEF
https://page2.yahoo.com/gr
Null
https://page3.google.com/hr
Please let me know, how to get multiple regex pattern or is their any other easy way to do this?
Thanks

You may use
val rx = "(?:href|img src)=\"(.*?)\"".r
val results = rx.findAllMatchIn(s).map(_ group 1)
// println(results.mkString(", ")) prints:
// https://page1.google.com/ab-cd/ABCDEF,
// https://page2.yahoo.com/gr,
// https://image01.google.com/gr/content/attachment/987654321,
// https://page3.google.com/hr
See the Scala demo
Details
(?:href|img src)=\"(.*?)\" matches either href or img src, then a =", and then captures any 0+ chars other than line break chars as few as possible into Group 1, and then a " is matched
With .findAllIn, you get all matches, then .map(_ group 1) only fetches Group 1 values.

Related

Scala regex get parameters in path

regex noob here.
example path:
home://Joseph/age=20/race=human/height=170/etc
Using regex, how do I grab everything after the "=" between the /Joseph/ path and /etc? I'm trying to create a list like
[20, human, 170]
So far I have
val pattern = ("""(?<=Joseph/)[^/]*""").r
val matches = pattern.findAllIn(path)
The pattern lets me just get "age=20" but I thought findAllIn would let me find all of the "parameter=" matches. And after that, I'm not sure how I would use regex to just obtain the "20" in "age=20", etc.
Code
See regex in use here
(?:(?<=/Joseph/)|\G(?!\A)/)[^=]+=([^=/]+)
Usage
See code in use here
object Main extends App {
val path = "home://Joseph/age=20/race=human/height=170/etc"
val pattern = ("""(?:(?<=/Joseph/)|\G(?!\A)/)[^=]+=([^=/]+)""").r
pattern.findAllIn(path).matchData foreach {
m => println(m.group(1))
}
}
Results
Input
home://Joseph/age=20/race=human/height=170/etc
Output
20
human
170
Explanation
(?:(?<=/Joseph/)|\G(?!\A)/) Match the following
(?<=/Joseph/) Positive lookbehind ensuring what precedes matches /Joseph/ literally
\G(?!\A)/ Assert position at the end of the previous match and match / literally
[^=]+ Match one or more of any character except =
= Match this literally
([^=/]+) Capture one or more of any character except = and / into capture group 1
Your pattern looks for the pattern directly after Joseph/, which is why only age=20 matched, maybe just look after =?
val s = "home://Joseph/age=20/race=human/height=170/etc"
// s: String = home://Joseph/age=20/race=human/height=170/etc
val pattern = "(?<==)[^/]*".r
// pattern: scala.util.matching.Regex = (?<==)[^/]*
pattern.findAllIn(s).toList
// res3: List[String] = List(20, human, 170)

Extract variables from string with Regex

I'm trying to extract from a string variables with the following format: ${var}
Given this string:
val s = "This is a string with ${var1} and ${var2} and {var3}"
The result should be
List("var1","var2")
This is the attempt, it ends in an exception. What's wrong with this regex?
val pattern = """\${([^\s}]+)(?=})""".r
val s = "This is a string with ${var1} and ${var2} and {var3}"
val vals = pattern.findAllIn(s)
println(vals.toList)
and the exception:
Exception in thread "main" java.util.regex.PatternSyntaxException:
Illegal repetition near index 1 \${([^\s}]+)(?=})
NOTE :- { in regex have special meaning. It denotes range. e.g. a{2,10} denotes match a in between 2 to 10 times. So you need to escape {.
Solution 1
val pattern = """\$\{([^\s}]+)(?=})""".r
You need to access the first capturing group for finding the result and then change it to list.
Solution 2
You can also use lookbehind like
val pattern = """(?<=\$\{)[^\s}]+(?=})""".r
Ideone Demo

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

Using regex in Scala to group and pattern match

I need to process phone numbers using regex and group them by (country code) (area code) (number). The input format:
country code: between 1-3 digits
, area code: between 1-3 digits
, number: between 4-10 digits
Examples:
1 877 2638277
91-011-23413627
And then I need to print out the groups like this:
CC=91,AC=011,Number=23413627
This is what I have so far:
String s = readLine
val pattern = """([0-9]{1,3})[ -]([0-9]{1,3})[ -]([0-9]{4,10})""".r
val ret = pattern.findAllIn(s)
println("CC=" + ret.group(1) + "AC=" + ret.group(2) + "Number=" + ret.group(3));
The compiler said "empty iterator." I also tried:
val (cc,ac,n) = s
and that didn't work either. How to fix this?
The problem is with your pattern. I would recommend using some tool like RegexPal to test them. Put the pattern in the first text box and your provided examples in the second one. It will highlight the matched parts.
You added spaces between your groups and [ -] separators, and it was expecting spaces there. The correct pattern is:
val pattern = """([0-9]{1,3})[ -]([0-9]{1,3})[ -]([0-9]{4,10})""".r
Also if you want to explicitly get groups then you want to get a Match returned. For an example the findFirstMatchIn function returns the first optional Match or the findAllMatchIn returns a list of matches:
val allMatches = pattern.findAllMatchIn(s)
allMatches.foreach { m =>
println("CC=" + m.group(1) + "AC=" + m.group(2) + "Number=" + m.group(3))
}
val matched = pattern.findFirstMatchIn(s)
matched match {
case Some(m) =>
println("CC=" + m.group(1) + "AC=" + m.group(2) + "Number=" + m.group(3))
case None =>
println("There wasn't a match!")
}
I see you also tried extracting the string into variables. You have to use the Regex extractor in the following way:
val Pattern = """([0-9]{1,3})[ -]([0-9]{1,3})[ -]([0-9]{4,10})""".r
val Pattern(cc, ac, n) = s
println(s"CC=${cc}AC=${ac}Number=$n")
And if you want to handle errors:
s match {
case Pattern(cc, ac, n) =>
println(s"CC=${cc}AC=${ac}Number=$n")
case _ =>
println("No match!")
}
Also you can also take a look at string interpolation to make your strings easier to understand: s"..."

how do I extract substring (group) using regex without knowing if regex matches?

I want to use this
val r = """^myprefix:(.*)""".r
val r(suffix) = line
println(suffix)
But it gives an error when the string doesn't match. How do I use a similar construct where matching is optional?
Edit: To make it clear, I need the group (.*)
You can extract match groups via pattern matching.
val r = """^myprefix:(.*)""".r
line match {
case r(group) => group
case _ => ""
}
Another way using Option:
Option(line) collect { case r(group) => group }
"""^myprefix:(.*)""".r // Regex
.findFirstMatchIn(line) // Option[Match]
.map(_ group 1) // Option[String]
This has the advantage that you can write it as a one-liner without needing to assign the regex to an intermediate value r.
In case you're wondering, group 0 is the matched string while group 1 etc are the capture groups.
try
r.findFirstIn(line)
UPD:
scala> val rgx = """^myprefix:(.*)""".r
rgx: scala.util.matching.Regex = ^myprefix:(.*)
scala> val line = "myprefix:value"
line: java.lang.String = myprefix:value
scala> for (rgx(group) <- rgx.findFirstIn(line)) yield group
res0: Option[String] = Some(value)