2016-11-05 2 views
2

Я хочу, чтобы извлечь дату (например, 2015-01-01) из нескольких строк, которые имеют форму в Scala:дата выписки из строки в Scala эффективна

val s = "basedir/somedir/tmp/BLAH/2015-01-01.txt" 

Я знаю, что я могу сделать основную операцию со строками сплит-дифферент-стрип для достижения этого, но есть ли более чистый способ сделать это в Scala? Могу ли я использовать некоторые «скрытые функции» регулярных выражений, которые предлагает Scala для этого?

Я попытался это без особого успеха:

val s = "basedir/somedir/tmp/BLAH/2015-01-01.txt" 
val regex = "(\\d+)-(\\d+)-(\\d+).txt" 
val regex(year, month, date) = s 

ответ

2

Используйте соответствующий шаблон, используя регулярное выражение Extractor

val regex = ".*/(\\d{4}-\\d{2}-\\d{2}).txt".r //remove/after .* if you think its not needed. 

str match { 
    case regex(date) => Some(date) 
    case _ => None 
} 

Использование выше кода вместо ниже, потому что ниже один вызовет ошибку совпадения во время выполнения.

val regex(a) = "basedir/somedir/tmp/BLAH/2015-01-01.txt" 

Вместо .* перед регулярным выражением. Вы можете использовать unanchored.

val regex = "(\\d{4}-\\d{2}-\\d{2}).txt".r.unanchored 

Скала РЕПЛ

scala> val regex = "(\\d{4}-\\d{2}-\\d{2}).txt".r.unanchored 
regex: scala.util.matching.UnanchoredRegex = (\d{4}-\d{2}-\d{2}).txt 

scala> val regex(a) = "basedir/somedir/tmp/BLAH/2015-01-01.txt" 
a: String = 2015-01-01 

Скала РЕПЛ

scala> val regex = ".*/(\\d{4}-\\d{2}-\\d{2}).txt".r 
regex: scala.util.matching.Regex = .*/(\d{4}-\d{2}-\d{2}).txt 

scala> val regex(a) = "basedir/somedir/tmp/BLAH/2015-01-01.txt" 
a: String = 2015-01-01 

Скала РЕПЛ

scala> val str = "basedir/somedir/tmp/BLAH/2015-01-01.txt" 
str: String = basedir/somedir/tmp/BLAH/2015-01-01.txt 

scala> val regex = ".*/(\\d{4}-\\d{2}-\\d{2}).txt".r 
regex: scala.util.matching.Regex = .*/(\d{4}-\d{2}-\d{2}).txt 

scala> 
    |  str match { 
    |  case regex(date) => Some(date) 
    |  case _ => None 
    |  } 
res21: Option[String] = Some(2015-01-01) 

Если вы хотите, чтобы соответствовать каталог, а затем

scala val regex = ".*/(.*)/(\\d{4}-\\d{2}-\\d{2}).txt".r 
regex: scala.util.matching.Regex = .*/(.*)/(\d{4}-\d{2}-\d{2}).txt 

scala> val s = "basedir/somedir/tmp/BLAH/2015-01-01.txt" 
s: String = "basedir/somedir/tmp/BLAH/2015-01-01.txt" 

scala> val regex(dir, date) = s 
dir: String = "BLAH" 
date: String = "2015-01-01" 
+0

Что делать, если я также хочу извлечь каталог, в котором находится файл «YYYY-MM-dd.txt»? Итак, скажем, я хочу извлечь («BLAH», «2015-01-01») в качестве кортежа вместо «2015-01-01»? Спасибо. –

+0

@ Darth.Vader отредактировал ответ и добавил, что хотите, чтобы вы посмотрите в конце. Посмотрите – pamu

+0

@ Darth.Vader в основном меняет регулярное выражение, чтобы включить dir также – pamu

0

Вчера я был осуждён разобрать некоторые файлы журнала с тремя или четырьмя различными представлениями времени в каждой строке.

Я рекомендую минимальное регулярное выражение и максимальные типизированные вещи.

$ scala 
Welcome to Scala 2.12.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_101). 
Type in expressions for evaluation. Or try :help. 

scala> val s = "basedir/somedir/tmp/BLAH/2015-01-01.txt" 
s: String = basedir/somedir/tmp/BLAH/2015-01-01.txt 

scala> val r = raw".*/([\d-]*)\.txt".r 
r: scala.util.matching.Regex = .*/([\d-]*)\.txt 

scala> val r(date) = s 
date: String = 2015-01-01 

scala> import java.time._, format._, DateTimeFormatter._ 
import java.time._ 
import format._ 
import DateTimeFormatter._ 

scala> ISO_LOCAL_DATE.parse(date) 
res0: java.time.temporal.TemporalAccessor = {},ISO resolved to 2015-01-01 

scala> Instant.from(res0) 
java.time.DateTimeException: Unable to obtain Instant from TemporalAccessor: {},ISO resolved to 2015-01-01 of type java.time.format.Parsed 
    at java.time.Instant.from(Instant.java:378) 
    ... 27 elided 
Caused by: java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: InstantSeconds 
    at java.time.format.Parsed.getLong(Parsed.java:203) 
    at java.time.Instant.from(Instant.java:373) 
    ... 27 more 

scala> LocalDate.from(res0) 
res2: java.time.LocalDate = 2015-01-01 

Другие варианты для удобства:

scala> object LocalDateX { def unapply(s: String): Option[LocalDate] = util.Try(LocalDate.from(ISO_LOCAL_DATE.parse(s))).toOption } 
defined object LocalDateX 

scala> val r(LocalDateX(date)) = s 
date: java.time.LocalDate = 2015-01-01 

или

scala> implicit class RContext(val sc: StringContext) { 
    | object r { 
    | def apply(args: Any*) = sc.s(args: _*) 
    | def unapplySeq(s: String) = sc.parts.mkString("(.+)").r.unapplySeq(s) 
    | }} 
defined class RContext 

scala> val r".*/${LocalDateX(date)}.txt" = s 
date: java.time.LocalDate = 2015-01-01 
+0

Я думаю, что есть обертки вокруг времени libs, но я не знаю, предоставляют ли они удобные экстракторы. –

-1

Вы можете сделать это в две строки.

import java.text.SimpleDateFormat 
val date_format = new java.text.SimpleDateFormat("yyyy-MM-dd") 
date_format.format(date_format.parse("2017-10-26 09:15:54.127")) 
res39: String = 2017-10-26 
Смежные вопросы