(重新)使用DateTimeFormatter解析日期范围或将DateTimeFormatter与正则表达式混合使用

时间:2018-04-03 15:35:09

标签: java regex date localdate

我有以下字符串表示我需要解析的日期范围:

import { combineReducers } from 'redux'
import {ADD_TODO, 
        FORK_TODO, 
        ADDED_BUTTON, 
        TOGGLE_BUTTON,
        EDIT_TODO, 
        DELETE_TODO, 
        FILTER_TODO_UP, 
        FILTER_TODO_DOWN,
        CHANGE_STATUS,
        VISIBLE_TODO_ALL,
        VISIBLE_TODO_ACTIVE,
        VISIBLE_TODO_DONED } from '../Variables/Variables'

const initialState = {
    iteams: {
        todos:[],
        buttons:[]
    }
}

function TodoApp(state, action) {
    if (typeof state === 'undefined') {
        return initialState;
    }

    switch (action.type) {
        case ADD_TODO:
        console.log(state.iteams);
            return Object.assign({}, state, {
                iteams: {
                    todos: [
                        ...state.iteams.todos, 
                        {
                            id: action.id,
                            text: action.text + '___' + action.id,
                            status: action.status
                        }
                    ],
                    buttons: [
                        ...state.iteams.buttons, 
                        {
                            id: action.id,
                            done: false,
                            status: action.status
                        }
                    ]
                }
            });
        case CHANGE_STATUS:
        console.log(state.iteams, action.status);
            return {
                iteams: {
                    todos: [
                        ...state.iteams.todos.map(todo => {
                            return (todo.id === parseInt(action.id) 
                                    && todo.status !== action.status) 
                                ? {...state.iteams.todo, 
                                    id: todo.id,
                                    text: todo.text,
                                    status: action.status
                                } : todo
                            })
                    ],
                    buttons: [
                        ...state.iteams.buttons.map(button => {
                            return (button.id === parseInt(action.id) 
                                    && button.status !== action.status) ?
                                {...state.iteams.button, 
                                    id: button.id,
                                    done: button.done,
                                    status: action.status
                                } : button
                        })
                    ]
                }
            };
        case VISIBLE_TODO_ALL:
        console.log('VISIBLE_TODO_ALL', state.iteams);
            return Object.assign({}, {
                ...state
            });
        case VISIBLE_TODO_ACTIVE:
        console.log('VISIBLE_TODO_ACTIVE', state.iteams);
            return Object.assign({}, {
                iteams: {
                    todos: state.iteams.todos.filter(iteam => 
                        iteam.status === 'active'

                    ),
                    buttons: state.iteams.buttons.filter(button => 
                        button.status === 'active'
                    )
                }
            });
        case VISIBLE_TODO_DONED:
        console.log('VISIBLE_TODO_DONED', state.iteams);
            return Object.assign({}, {
                iteams: {
                    todos: state.iteams.todos.filter(iteam => 
                        iteam.status === 'done'
                    ),
                    buttons: state.iteams.buttons.filter(button => 
                        button.status === 'done'
                    )
                }
            });
        default: 
            return state;
    }
}

export default TodoApp

它由2个ISO日期字符串组成,以2018-10-20:2019-10-20

分隔

通过将重复的日期范围与其他文本混合,字符串会变得更复杂。这可以通过正则表达式完成。

然而,鉴于最新的Java具有日期/时间支持,大多数编码人员在这里和其他地方都欣喜若狂,是否可以使用:的解析器或自定义LocalDate为了识别我的String中哪些位是ISO-date的候选者并捕获它们?

更好的是,如何从DateTimeFormatter(标识ISO日期的正则表达式,假设有一个)中提取验证正则表达式,并将其与我自己的正则表达式合并/编译为字符串的其余部分

我觉得在我的代码中编写另一个ISO-date正则表达式时感觉很舒服,因为Java中已经存在一个正则表达式而且我只是重复使用它。

请注意,我不是要求正则表达式。我能做到。

另请注意,我的示例字符串可以包含其他日期/时间格式,例如时区和毫秒以及所有的哨声。

2 个答案:

答案 0 :(得分:0)

Regex + Date Parser是正确的选择。

您必须自己编写正则表达式,因为日期解析器不使用正则表达式。

您的选择是否正则表达式可以简单,例如月份\d{2},让日期解析器验证号码范围,或者是否必须更严格,例如(?:0[1-9]|1[0-2])01 - 12)。在正则表达式中不应该进行范围检查,例如28 vs 30 vs 31天。让日期解析器处理它,并且因为一些值范围由日期解析器处理,所以也可以让它全部处理它们,即一个简单的正则表达式完全没问题。

答案 1 :(得分:0)

实际上,DateTimeFormatter没有内部正则表达式。它uses a CompositePrinterParser,后者又使用array of DateTimePrinterParser instancesinner interface of DateTimeFormatterBuilder),其中每个实例负责解析/格式化特定字段。

IMO,正则表达式不是这里最好的方法。如果您知道所有日期都以:分隔,为什么不简单地拆分字符串并尝试单独解析这些部分?这样的事情:

String dates = // big string with dates separated by :

DateTimeFormatter parser = // create a formatter for your patterns
for (String s : dates.split(":")) {
    parser.parse(s); // if "s" is invalid, it throws exception
}

如果您只想验证字符串,如上所述调用parse就足够了 - 如果字符串无效,它将抛出异常。

要支持多种格式,您可以使用DateTimeFormatterBuilder::appendOptional。例如:

DateTimeFormatter parser = new DateTimeFormatterBuilder()
    // full ISO8601 with date/time and UTC offset (ex: 2011-12-03T10:15:30+01:00)
    .appendOptional(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
    // date/time without UTC offset (ex: 2011-12-03T10:15:30)
    .appendOptional(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
    // just date (ex: 2011-12-03)
    .appendOptional(DateTimeFormatter.ISO_LOCAL_DATE)
    // some custom format (day/month/year)
    .appendOptional(DateTimeFormatter.ofPattern("dd/MM/yyyy"))
    // ... add as many you need
    // create formatter
    .toFormatter();

支持多种格式的正则表达式(正如你所说,“其他日期/时间格式,例如时区和毫秒以及所有哨声”)是可能的,但正则表达式不适合验证日期 - 例如第零天,日> 30对于非闰年2月29日的所有月份无效,分钟> 60等。

DateTimeFormatter将验证所有这些棘手的细节,而正则表达式只能保证您的数字和分隔符位于正确的位置,并且不会验证这些值。因此,无论正则表达式如何,你都必须解析日期(在这种情况下,恕我直言,正则表达式使用正则表达式无用)。