2011-05-12 69 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 
    }