2

I have a string, say var str = "hello, world" and a List of Regex patterns

val patterns = List(new Regex("hello, (.*)", "substr"), new Regex("hi, (.*)", "substr"))

How can I match str against these patterns? Now instead of using List of patterns I'm doing the following:

val pattern1 = new Regex("hello, (.*)", "substr")
val pattern2 = new Regex("hi, (.*)", "substr")
var someVar = "something"
var someVar2 = "something else"
str match {
    case pattern1(substr) => { someVar = substr; someVar2 = "someValue" }
    case pattern2(substr) => { someVar = substr; someVar2 = "someOtherValue" }

}

Appendix:

I forgot to mention one important thing: in fact there are several lists of patterns. And someVar2 takes its value depending on the list from which the first pattern match occurred. It does not matter for me whether to use nested lists like List(List(new Regex(...), new Regex(...), ...), List(new Regex(...), new Regex(...), ...)) or to use separate val for each list of patterns like val patterns1 = List(new Regex(...), ...); val patterns2 = List(new Regex(...), ...).

4
  • 2
    What do you want to happen if several patterns match? Commented Aug 27, 2013 at 14:00
  • Well, what happens in my current approach? Only first of them matches, the rest is ignored. This just perfectly meets my requirements :) Commented Aug 27, 2013 at 14:04
  • The appendix makes me appreciate project managers who can express requirements succinctly and precisely. Commented Aug 27, 2013 at 14:26
  • Well, with Shadowlands' answer the appendix appears not to be so important after all :) Just as I originally assumed. Commented Aug 27, 2013 at 14:39

2 Answers 2

7

Try this:

scala> patterns.collectFirst{ p => str match { case p(substr) => substr } }
res3: Option[String] = Some(world)

scala> val str2 = "hi, Fred"
str2: String = hi, Fred

scala> patterns.collectFirst{ p => str2 match { case p(substr) => substr } }
res4: Option[String] = Some(Fred)

EDIT: updating to account for changed requirements...

Given:

val patternMapping = Map(("marker1" -> patterns), ("marker2" -> patterns2), ...)

You should be able to nest the collectFirst calls, resulting in something like this:

scala> patternMapping.collectFirst{ case (mark, pList) => pList.collectFirst{ p => str match { case p(substr) => (mark -> substr) } } }.flatten
res5: Option[(String, String)] = Some((marker1,world))

I suspect this could probably be played around with and neatened up, but should give the general idea.

Sign up to request clarification or add additional context in comments.

1 Comment

I love this approach! It looks so "functional-ish"! Thank you again, made this the accepted answer.
3

Well you yourself solved it. There are many ways. One of the idiomatic way is:

 val patterns = List(new Regex("hello, (.*)", "substr"), new Regex("hi, (.*)", "substr"))
 patterns.foreach{ x =>
   str match { 
          case x(substr) => { someVar = substr; someVar2 = "defaultValue" }
          case _ => ;     
       }
 }

In case, if you wish to replace defaultValue with the index of regex it matched then:

val  i = patterns.zipWithIndex
i.foreach{ x =>
       str match { 
              case x._1(substr) => { someVar = substr; someVar2 = "defaultValue - "+x._2 }
              case _ => ;     
           }
     }

1 Comment

What happens here if several patterns match? I suppose, the code within case block will be executed several times. What I need is to catch the first matched pattern and ignore the rest.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.