2013-05-13 148 views
1

我想创建一个程序来解析一个字符串中有意义的日期和时间。我希望能够给以下几种输入,并创建一个日期/时间对象:从字符串解析日期/时间?

5 o'clock 
5 p.m. 
5 a.m. 
5 
530 
530 a.m. 
530 p.m. 
Tuesday at [insert any above string here] 
the 30th at [same as above] 
May 12th at [same as above] 
today at [same as above] 
tomorrow at [same as above] 

不包含日/日期可以假设今天是任何字符串,任何时间没有上午/下午指定可以被认为是在上午9点到下午8点59分之间发生。 我很快就意识到什么乱七八糟的在写代码的这一部分后成为:

private void createEvent(String phrase) { 
    int hour; 
    int day = 0; 
    String dayOfWeek = ""; 

    if (phrase.contains("o'clock")) { 
     hour = Integer.parseInt(phrase.substring(phrase.indexOf("o'clock")-3, phrase.indexOf("o'clock")-1).trim()); 
     out.write(""+hour); 
    } 

    if (phrase.contains("tomorrow")) 
     day = (Calendar.DAY_OF_WEEK % 7)+1; 

    if (phrase.contains("sunday") || day == 1) { 
     dayOfWeek = "Sunday"; day = 1; } 
    else if (phrase.contains("monday") || day == 2) { 
     dayOfWeek = "Monday"; day = 2; } 
    else if (phrase.contains("tuesday") || day == 3) { 
     dayOfWeek = "Tuesday"; day = 3; } 
    else if (phrase.contains("wednesday") || day == 4) { 
     dayOfWeek = "Wednesday"; day = 4; } 
    else if (phrase.contains("thursday") || day == 5) { 
     dayOfWeek = "Thursday"; day = 5; } 
    else if (phrase.contains("friday") || day == 6) { 
     dayOfWeek = "Friday"; day = 6; } 
    else if (phrase.contains("saturday") || day == 7) { 
     dayOfWeek = "Saturday"; day = 7; } 
    else { 
     dayOfWeek = "Today"; day = 0; }  
} 

任何人都可以提供一些方向?

+1

我会专注于每个案件seperatly,也许创建一个简单的'格式化工具'的基本目的。将它们全部添加到中央'FormatFactory'中。这将允许您根据需要增加可能的格式化器数量(或者在需要时排除一些格式器) – MadProgrammer 2013-05-13 05:42:24

+0

您的字符串中可能还有其他什么?整个字符串是否与时间有关,还是可能包含其他信息?例如:“我会在五点钟在车站接你” – GHC 2013-05-13 05:45:23

回答

3

你可以使用日期格式

String now = new Date().toString(); 
SimpleDateFormat format = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy"); 
Date date = format.parse(now); 

也许你可以建立提前几个格式,然后比较分析的日期。

检查教程这里:http://www.xyzws.com/Javafaq/how-to-use-simpledateformat-class-formating-parsing-date-and-time/142

+0

不会解析“a.m.”或“下午”。 “明天”呢? – MadProgrammer 2013-05-13 06:00:26

+0

如果字符串格式没有限制,编写代码来处理所有情况是不可能的。如果你想解析用户输入的所有内容,它将成为关于自然语言处理的一个问题... – ltebean 2013-05-13 06:09:20

+0

然后说尽可能多的 – MadProgrammer 2013-05-13 06:15:28

2

下打破你的问题转化为可管理的块...

我会通过提供这,因为你需要,你可以添加新的格式化的手段开始。

我也试着找到重用现有的代码。时间对于你的问题是一个非常一致的方面。

这将导致我提供某种形式的统一格式工厂的概念(使管理更容易),但个性化需求分解成更小的可管理的块

import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.Calendar; 
import java.util.Date; 
import java.util.List; 

public class CustomDateFormatter { 

    public static void main(String[] args) { 
     new CustomDateFormatter(); 
    } 

    public CustomDateFormatter() { 

     String values[] = new String[]{ 
      "5 o'clock", 
      "5 p.m.", 
      "5 a.m.", 
      "5", 
      "530", 
      "530 a.m.", 
      "530 p.m.",}; 

     for (String value : values) { 
      System.out.println(value + " = " + CustomFormatFactory.format(value)); 
     } 
    } 

    public static class CustomFormatFactory { 

     private static List<CustomFormat> formatters = new ArrayList<>(); 

     public static Date format(String value) { 
      Date date = null; 
      for (CustomFormat format : formatters) { 
       if (format.canFormat(value)) { 
        date = format.format(value); 
        if (date != null) { 
         break; 
        } 
       } 
      } 
      return date; 
     } 

     protected static boolean formatTime(String value, Calendar cal) { 
      boolean formatted = false; 
      if (Character.isDigit(value.charAt(0))) { 
       formatted = true; 
       StringBuilder timePart = new StringBuilder(4); 
       int index = 0; 
       while (index < value.length() && Character.isDigit(value.charAt(index))) { 
        timePart.append(value.charAt(index)); 
        index++; 
       } 

       int hour = 0; 
       int min = 0; 
       if (timePart.length() < 3) { 
        hour = Integer.parseInt(timePart.toString()); 
       } else { 
        hour = Integer.parseInt(timePart.substring(0, timePart.length() - 2)); 
        min = Integer.parseInt(timePart.substring(timePart.length() - 2, 3)); 
       } 

       cal.set(Calendar.HOUR_OF_DAY, hour); 
       cal.set(Calendar.MINUTE, min); 
       cal.set(Calendar.MILLISECOND, 0); 

       String sufix = value.substring(timePart.length()).trim(); 
       if ("p.m.".equalsIgnoreCase(sufix) || "pm".equalsIgnoreCase(sufix)) { 
        cal.add(Calendar.HOUR, 12); 
       } 
      } 
      return formatted; 
     } 

     static { 
      formatters.add(new SimpleTimeFormat()); 
     } 
    } 

    public static interface CustomFormat { 

     public boolean canFormat(String value); 

     public Date format(String value); 
    } 

    public static class SimpleTimeFormat implements CustomFormat { 

     @Override 
     public boolean canFormat(String value) { 
      return format(value) != null; 
     } 

     @Override 
     public Date format(String value) { 
      Date date = null; 
      Calendar cal = Calendar.getInstance(); 
      if (CustomFormatFactory.formatTime(value, cal)) { 
       date = cal.getTime(); 
      } 
      return date; 
     } 
    } 
} 

对于扩展的日期格式,我会提取日期部分,根据日期生成Calendar,将时间分区提取为单独的String,并使用CustomFormatFactory.formatTime方法来格式化时间,从而使您不必每次重新编码它。

同样,日期格式化器可以在内部简单地拥有一个时间格式化器的实例,或者您可以将工厂设置为具有多个格式方法,一个需要时间值并通过可用时间格式化器循环......这会是我个人的选择;)