2011-05-12 96 views
5

我在电梯应用程序中有日期输入框,我想检查用户输入的日期格式是否正确:dd/mm/yyyy斯卡拉/电梯检查日期格式是否正确

如何在scala中编写正则表达式检查?我看过模式匹配的例子 - 但这似乎过于复杂。

PS:我不必使用正则表达式,欢迎任何其他替代方案!

回答

10

SimpleDateFormat是丑陋的(更令人不安的)非线程安全。如果你试图在2个或更多的线程中同时使用同一个实例,那么就会以非常不愉快的方式期待事情爆发。

JodaTime远远更好:

import org.joda.time.format._ 
val fmt = DateTimeFormat forPattern "dd/MM/yyyy" 
val input = "12/05/2009" 
val output = fmt parseDateTime input 

如果它抛出一个IllegalArgumentException,然后将日期无效。

因为我怀疑你会想知道实际的日期,如果它是有效的,你可能想要返回一个Option[DateTime],如果它是无效的None

def parseDate(input: String) = try { 
    Some(fmt parseDateTime input) 
} catch { 
    case e: IllegalArgumentException => None 
} 

另外,使用Either来获得实际的异常,如果不能格式化:

def parseDate(input: String) = try { 
    Right(fmt parseDateTime input) 
} catch { 
    case e: IllegalArgumentException => Left(e) 
} 

UPDATE

要再使用Either,你有两个主要的策略:

地图两面之一:

parseDate(input).left map (_.getMessage) 
//will convert the Either[IllegalArgumentException, DateTime] 
//to an Either[String, DateTime] 

把它折叠:

parseDate(input) fold (
    _ => S.error(
    "birthdate", 
    "Invalid date. Please enter date in the form dd/mm/yyyy."), 
    dt => successFunc(dt) 
) 

当然,两者可以组成:

parseDate(input).left map (_.getMessage) fold (
    errMsg => S.error("birthdate", errMsg), //if failure (Left by convention) 
    dt => successFunc(dt) //if success (Right by convention) 
) 
+0

只需要注意一下,如果在Lift中使用它,那么使用Box和Option在包装方面更好。 Box将允许您存储错误。 – andyczerwonka 2011-05-17 16:25:09

+1

@arcticpenguin - 我个人非常不喜欢Lift的'Box'构造,并且在被迫接受API的东西时会尽早将它们转换为'Option'。如果我还需要单向追踪异常,那么我会优先使用'Either',这不仅仅是因为我可以轻松将异常映射到'String'或其他类型,以便记录或向最终用户呈现。 – 2011-05-17 16:35:24

+0

我并不反对。伟大的一点。 – andyczerwonka 2011-05-17 16:47:13

1

我不会使用正则表达式,而是使用SimpleDateFormat(这不是那么简单,我们将会看到)。

正则表达式允许28和30作为一天,但不是38,不同的月份长度和闰年,可能是一个有趣的挑战,但不适用于真实世界的代码。

val df = new java.text.SimpleDateFormat ("dd/MM/yyyy") 

(我假设M在大月份,而不是在小分钟)。

现在,让我们开始了一个错误:

scala> df.parse ("09/13/2001")         
res255: java.util.Date = Wed Jan 09 00:00:00 CET 2002 

hoppla - 这是非常宽容的,和周围包裹个月到明年。但是,我们可以用第二格式化过程得到它:

scala> val sInput = "13/09/2001" 
sInput: java.lang.String = 13/09/2001 

scala> sInput.equals (df.format (df.parse (sInput))) 
res259: Boolean = true 

scala> val sInput = "09/13/2001"      
sInput: java.lang.String = 09/13/2001 

scala> sInput.equals (df.format (df.parse (sInput))) 
res260: Boolean = false 

我希望你不绑定到正则表达式,并且可以使用它。

+0

哦不,我可以使用任何我喜欢的东西。我修改了这个问题。这看起来很有趣,谢谢! – drozzy 2011-05-12 19:04:27

+0

所以 - 你是否在说要检查它是否是错误的 - 我应该匹配它 - 并将其转换回字符串? – drozzy 2011-05-12 19:05:49

+0

另外 - 这是否验证日期是“真实”日期,还是只符合一般语法。像我可以有2011年4月31日? – drozzy 2011-05-17 13:08:42

1

由于用户未知写,你应该使用它知道如何正确处理日期一些库包括每个特定月份和闰年的日期。

SimpleDateFormat对于字段翻转并不是非常直观,并且最初通过滚动其他字段来接受错误的日期。为了防止它这样做,你必须在其上调用setLenient(false)。也请记住,SimpleDateFormat不是线程安全的,所以你需要你想用的时候就创建一个新的实例:

def validate(date: String) = try { 
    val df = new SimpleDateFormat("dd/MM/yyyy") 
    df.setLenient(false) 
    df.parse(date) 
    true 
    } catch { 
    case e: ParseException => false 
    } 

另外,您还可以使用Joda Time这是比Java的日期更直观一点API和提供线程安全的日期格式:

val format = DateTimeFormat.forPattern("dd/MM/yyyy") 

def validate(date: String) = try { 
    format.parseMillis(date) 
    true 
    } 
    catch { 
    case e: IllegalArgumentException => false 
    } 
1

由此我们可以在字符串验证日期,以及我们得到通过像“DD/MM/YYYY”格式解析预产期的响应。

try { val format = DateTimeFormat.forPattern("dd/MM/yyyy") 
    format.parseMillis(dateInString) 
    val df = new SimpleDateFormat("dd/MM/yyyy") 
    val newDate = df.parse(dateInString) 
    true 
    } catch { 
     case e: ParseException => false 

     case e: IllegalArgumentException => false 
    } 
0

这是一个很好的做法中的对象定义DateTimeFormatter实例,因为它是线程安全的,不可变的。

object DateOfBirth{ 
    import org.joda.time.format.DateTimeFormat 
    import scala.util.Try 
    val fmt = DateTimeFormat forPattern "MM/dd/yyyy" 
    def validate(date: String) = Try(fmt.parseDateTime(date)).isSuccess 
    }