user2130187
user2130187

Reputation: 21

Scala regex pattern match is working properly or not?

I'm new to Scala but I was told that "You are checking if "Toronto Raptor" == matchNY." for the following code snippet @ https://issues.scala-lang.org/browse/SI-7210, and I really don't have any idea why "Totonto Raptor" is the only string chosen in the for loop to be matched with the regular expression, can someone explain this to me please ?
Thanks. David

    val matchNY = "^.*New.*$".r

    val teams = List(
        "Toronto Raptor",
        "New York Nets",
        "San Francisco 49ers",
        "Dallas Mavericks"
    )

    for (team <- teams) {
        team match {
            case `matchNY` => println("Go New York.")
            case _ => println("Boo")
        }
    }

Note-1: The usage of backticks is explained here @ http://alvinalexander.com/scala/scala-unreachable-code-due-to-variable-pattern-message

Upvotes: 2

Views: 1735

Answers (3)

Faiz
Faiz

Reputation: 16255

I am assuming you meant

val matchNY = "^.*New.*$".r

and not ^.New.$, if you were expecting to match strings containing New.

In Scala, a block of case statements can be thought of as a sequence of partial functions.

In your example,

case `matchNY` => // ...

Translates to something like:

case x if x == matchNY  => // .. 

So that will try to match the String "Toronto Raptor" with the Regexp object ^.*New.*$ using equality:

"Toronto Raptor" == ("^.*New.*$".r) 

Which doesn't match because a String and a Regexp object are 2 different things.

The same goes for any of the other Strings in the list:

"New York Nets" !=  ("^.*New.*$".r)

Which doesn't match either. The way to use a regexp as a match in a case statement is:

case matchNY() => // .... Note the ()

Which, under the hood is (roughly) equivalant to something like

case x matchNY.unapplySeq(x).isDefined =>  // ...

Regexps in case statements are implemented as Extractor Objects with an unapplySeq method. The last expression shows what the previous translates into.

If matchNY had a capture such as:

val matchNY = "^.*New York\s(.*)$".r

Then you could use it to extract the captured match:

case matchNY(something) => // 'something' is a String variable 
                           // with value "Nets"

Side Note

Your example could be condensed to

teams foreach { 
   case matchNY() => println("Go New York.")
   case _ => println("Boo")
}

Upvotes: 5

Brian Hsu
Brian Hsu

Reputation: 8821

Yes, it is working properly. The magic behinds pattern matching is something called extractors.

If you dig through the ScalaDoc of Regex, you will see that it only defined unapplySeq, but not unapply.

That means if you want use Regex at Pattern Matching, you should do the following (note the parentheses after matchNY) :

val matchNY = "^.*New.*$".r

val teams = List(
    "Toronto Raptor",
    "New York Nets",
    "San Francisco 49ers",
    "Dallas Mavericks"
)

for (team <- teams) {
    team match {
        case matchNY() => println("Go New York.")
        case _ => println("Boo")
    }
}

Otherwise, you are simply checking if the elements in the list is == matchNY, which is not what you want anyway.

Upvotes: 4

Noah
Noah

Reputation: 13959

In your for loop you're literally checking if each item in the list of teams is equal to the regex matchNY and every item in the list is checked not just "Toronto Raptor". This is equivalent to your for loop:

  for (team <- teams) {
    if (team == matchNY) println("Go New York.")
    else println("Boo")
  }

Which breaks down to this:

  if ("Toronto Raptor" == matchNY) println("Go New York.") else println("Boo")
  if ("New York Nets" == matchNY) println("Go New York.") else println("Boo")
  if ("San Francisco 49ers" == matchNY) println("Go New York.") else println("Boo")
  if ("Dallas Mavericks" == matchNY) println("Go New York.") else println("Boo")

What I think your looking for is if something matches you're regex. You can do something like this:

  for (team <- teams) {
    matchNY.findFirstMatchIn(team) match {
      case Some(teamMatch) => {
        println("Go New York.")
        println(teamMatch)
      }
      case _ => {
        println("Boo")
        println(team)
      }
    }
  }

Which prints out:

Boo
Toronto Raptor
Go New York.
New York Nets
Boo
San Francisco 49ers
Boo
Dallas Mavericks

Upvotes: 1

Related Questions