2

What am I doing wrong here:

val pattern = "([1-7]),([0-1][0-9]|[2][0-3])([0-1][0-9]|[2][0-3])".r
val pattern(count, fruit) = "7,2323"

gives:

[info]   Scenario: For a set of combination of hour formats, map them to the expected 24 hours format1 *** FAILED ***
[info]   scala.MatchError: 7,2323 (of class java.lang.String)
[info]   at com.mf.location.os.service.util.HoursFormatUtil$.fromHours(HoursFormatUtil.scala:55)
[info]   at com.mf.location.os.service.util.HoursFormatUtilSpec.$anonfun$new$9(HoursFormatUtilSpec.scala:71)
[info]   at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
[info]   at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
[info]   at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
[info]   at org.scalatest.Transformer.apply(Transformer.scala:22)
[info]   at org.scalatest.Transformer.apply(Transformer.scala:20)
[info]   at org.scalatest.featurespec.AnyFeatureSpecLike$$anon$1.apply(AnyFeatureSpecLike.scala:257)
[info]   at org.scalatest.TestSuite.withFixture(TestSuite.scala:196)
[info]   at org.scalatest.TestSuite.withFixture$(TestSuite.scala:195)

However println(s"matches ${pattern.matches("7,2323")}") returns true.

1
  • What is count and what is fruit here? Commented Feb 5, 2021 at 1:28

2 Answers 2

4

If your count value should be 7 and the fruit value should be 2323, you can use

val pattern = "([1-7]),((?:[0-1][0-9]|2[0-3]){2})".r
val line = "7,2323"
val (count, fruit) = line match {
  case pattern(count, fruit) => (count,fruit)
  case _ => ("","")
}
println(s"${count} and ${fruit}")
// => 7 and 2323

See the Scala demo.

Note the ([1-7]),((?:[0-1][0-9]|2[0-3]){2}) refactored pattern that now contains only two capturing groups. pattern(count, fruit) "extracts" the capturing group values and assigns them to count and fruit. If there is no match, these variable will be empty strings.

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

Comments

3

Just to add on top of the great answer by @Wiktor, please note that in your regex, you expect 3 capturing groups, while you are trying to assign them into 2 variables. This is the reason you get a matching error.

"([1-7]),([0-1][0-9]|[2][0-3])([0-1][0-9]|[2][0-3])".r
 ↑     ↑ ↑                    ↑↑                   ↑
 group 1      group 2                 group 3

If for example you try to do:

val pattern = "([1-7]),([0-1][0-9]|[2][0-3])([0-1][0-9]|[2][0-3])".r
val pattern(count, fruit, other) = "7,2323"
println(s"count: $count fruit: $fruit other: $other")

The output is:

count: 7 fruit: 23 other: 23

However, when you later on do pattern.matches("7,2323") you get true, because there is a match. You just don't capture it by the correct groups amount.

Code run at Scastie.

2 Comments

The reason I went with match block is because an exception will be thrown if there is no match, try your code with a non-matching string like val pattern(count, fruit, other) = "7,233".
I know @WiktorStribiżew. I completely understand your answer and upvoted it. I tried to explain why there was no match and to show how this can be done in the OPs approach. If I had to choose one of our two solutions I'd choose yours.

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.