Regular expression matching and returning None in case of error

I have a very simple string of the form

YYYYMMDDHHMMSS
Basically a full date/time string. Say an example is

20170224134523
Above implies

year: 2017
month: 02
day:24
hour:13
min:45
sec:23
I want to split it so that i can have it in variables (year, month, day, hour, min, sec). This is in Scala I want to. I was thinking should I use a 6-Tuple and on the right side I will use a regex or what as the most efficient way. If I want to do it in a concise way is what I am trying to think. Little bad with regular expressions. Can anyone help?

I may want to have each variable in the 6-tuple as option type because otherwise that will also do my sanity check? Say if any variable comes out as None, I want to return None from the whole method in which I am writing this.

Assuming you are running java 8 I think the clearest way to do this would be to use the java.time library to parse the string - no need to reinvent the wheel.

You can then use Try to handle exceptions and convert to Option, and then use map to access the bits of the datetime you want. Roughly like this:

import java.time.LocalDateTime
import java.time.format.DateTimeFormatter

import scala.util.Try

val f = DateTimeFormatter.ofPattern("yyyyMMddHHmmss")

val dt1 = Try(LocalDateTime.parse("20170224134523", f)).toOption
// val dt2 = Try(LocalDateTime.parse("a20170224134523", f)).toOption 

// println(dt1) // Some(2017-02-24T13:45:23)
// println(dt2) // None

val optionThing: Option[Thing] = dt1.map(datetime => {
  val year = datetime.getYear
  val month = datetime.getMonth
  // and so on.    
  someFunctionReturningThing(year, month)
}) 

Hope that helps.

Brian

How about this? Made it a case class to give it more clarity than a Tuple6 would. I also named the capture groups which helps in RegExes when there are a bunch of groups. This will safely return a None when any input is off-pattern.

import scala.util.matching.Regex

case class DateTimeStr(year: Int, month: Int, day: Int, hour: Int, min: Int, sec: Int)

def parseDateTime (dateTimeStr: String = "20170224134523"): Option[DateTimeStr] = {
  val pattern = """(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})""".r("year", "month", "day", "hour", "min", "sec")
  pattern.findFirstMatchIn(dateTimeStr).fold[Option[DateTimeStr]](None)(result =>
  Some(
    DateTimeStr(
      result.group("year").toInt,
      result.group("month").toInt,
      result.group("day").toInt,
      result.group("hour").toInt,
      result.group("min").toInt,
      result.group("sec").toInt,
    )
    )
  )
}

parseDateTime("20170224134523")
parseDateTime()
parseDateTime("boo!")
res0: Option[DateTimeStr] = Some(DateTimeStr(2017,8,24,14,44,14))
res1: Option[DateTimeStr] = Some(DateTimeStr(2017,2,24,13,45,23))
res2: Option[DateTimeStr] = None

Thank you both. This forum is so great. I used to use stack overflow and it is also very helpful but this place is amazing. No one gives a hard time no matter how rookie the Q is and so many tricks to learn from all these answers. I am new to scala and have to deliver big features in office. I can of course get things done by writing something but these answers are a gem to learn doing things the “nice way”.

@bentio, I want to google more about the syntax of
val pattern = “”"(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})""".r(“year”, “month”, “day”, “hour”, “min”, “sec”)
What does the () after the “.r” really do? What is it I must read to know about that syntax

Kanwaljeet I agree about the comparison to here vs. SO.

“”“some_reg_ex”"".r is a canonical way to get a constructor of a Regex. So if you constructed it with Regex() those would be parameters to the constructor.

Read about it here: http://www.scala-lang.org/api/2.12.1/scala/util/matching/Regex.html (top of the page)

If you also meant RegEx syntax in general, I find this site invaluable for creating and debugging RegExes: https://regex101.com/ <-- The Quick Reference down in the lower right corner is super handy. I used that site to initially create and check the RegEx in my answer.

Do note that brians answer might be better if you take a less literal approach to answering your question. You are somewhat reinventing the wheel if you don’t take advantage of Java 8 Date.