在解析之前确定String是否是有效日期

Mor*_*ter 13 java parsing date

我有这种情况,我正在阅读包含存储为字符串字段的日期的130K记录.有些记录包含空格(nulls),有些包含这样的字符串:'dd-MMM-yy',有些包含'dd/MM/yyyy'.

我写了一个像这样的方法:

public Date parsedate(String date){

   if(date !== null){
      try{
        1. create a SimpleDateFormat object using 'dd-MMM-yy' as the pattern
        2. parse the date
        3. return the parsed date
      }catch(ParseException e){
          try{
              1. create a SimpleDateFormat object using 'dd/MM/yyy' as the pattern
              2. parse the date
              3. return parsed date
           }catch(ParseException e){
              return null
           }
      }
   }else{
      return null
   }

} 
Run Code Online (Sandbox Code Playgroud)

所以你可能已经发现了这个问题.我正在使用try .. catch作为我逻辑的一部分.最好是我可以事先确定String实际上包含某种格式的可解析日期然后尝试解析它.

那么,是否有一些API或库可以帮助解决这个问题?我不介意写几个不同的Parse类来处理不同的格式,然后创建一个工厂来选择正确的6,但是,我该如何确定哪一个?

谢谢.

cle*_*tus 7

在逻辑中使用try-catch不要太费劲:这是Java强迫你这样做的一种情况,所以你不能做很多事情.

但在这种情况下你可以改用DateFormat.parse(String, ParsePosition).


Apo*_*isp 7

有关如何使用类型消除try/catch块的概述,请参阅Java中的延迟错误处理Option.

功能Java是你的朋友.

本质上,您要做的是将日期解析包装在不抛出任何内容的函数中,但在其返回类型中指示解析是否成功.例如:

import fj.F; import fj.F2;
import fj.data.Option;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import static fj.Function.curry;
import static fj.Option.some;
import static fj.Option.none;
...

F<String, F<String, Option<Date>>> parseDate =
  curry(new F2<String, String, Option<Date>>() {
    public Option<Date> f(String pattern, String s) {
      try {
        return some(new SimpleDateFormat(pattern).parse(s));
      }
      catch (ParseException e) {
        return none();
      }
    }
  });
Run Code Online (Sandbox Code Playgroud)

好的,现在你有一个可重用的日期解析器,它不会抛出任何东西,但是通过返回一个类型的值来指示失败Option.None.以下是您使用它的方式:

import fj.data.List;
import static fj.data.Stream.stream;
import static fj.data.Option.isSome_;
....
public Option<Date> parseWithPatterns(String s, Stream<String> patterns) { 
  return stream(s).apply(patterns.map(parseDate)).find(isSome_()); 
}
Run Code Online (Sandbox Code Playgroud)

这将为您提供使用匹配的第一个模式解析的日期,或者类型为Option.None的值,这是类型安全的,而null则不是.

如果你想知道是什么Stream...... 这是一个懒惰的清单.这可确保您在第一次成功之后忽略模式.不需要做太多工作.

像这样调用你的函数:

for (Date d: parseWithPatterns(someString, stream("dd/MM/yyyy", "dd-MM-yyyy")) {
  // Do something with the date here.
}
Run Code Online (Sandbox Code Playgroud)

要么...

Option<Date> d = parseWithPatterns(someString,
                                   stream("dd/MM/yyyy", "dd-MM-yyyy"));
if (d.isNone()) {
  // Handle the case where neither pattern matches.
} 
else {
  // Do something with d.some()
}
Run Code Online (Sandbox Code Playgroud)


Joh*_*her 6

您可以利用正则表达式来确定字符串所处的格式,以及它是否与任何有效格式匹配.像这样的东西(未经测试):

(哎呀,我在检查你正在使用的语言之前用C#编写过这个.)

Regex test = new Regex(@"^(?:(?<formatA>\d{2}-[a-zA-Z]{3}-\d{2})|(?<formatB>\d{2}/\d{2}/\d{3}))$", RegexOption.Compiled);
Match match = test.Match(yourString);
if (match.Success)
{
    if (!string.IsNullOrEmpty(match.Groups["formatA"]))
    {
        // Use format A.
    }
    else if (!string.IsNullOrEmpty(match.Groups["formatB"]))
    {
        // Use format B.
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)