另一个版本:
static private String month = "(?<month>jan(uary)?|feb(ruary)?|mar(ch)?|apr(il)?|may|jun(e)?|jul(y)?|aug(ust)?|sep(t|tember)?|oct(ober)?|nov(ember)?|dec(ember)?)";
static private String suffix = "(?:st|nd|rd|th)";
static private String date = "(?<date>\\d{1,2})";
static private String year = "(?<year>\\d{4})";
// A month name (optionally followed by space followed by a date (optionally
// followed by a suffix or space and a comma) (optionally followed by space
// followed by a year))
static private String order1 = String.format(
"%s(?:\\s+%s(?:%s|\\s+,)?(?:\\s+%s)?)?", month, date, suffix,
year);
// A date followed by a suffix followed by a month (optionally followed by
// space and a comma) optionally followed by space and a year
static private String order2 = String.format(
"%s%s\\s+%s(?:\\s+,)?(?:\\s+%s)?", date, suffix, month, year);
是的,没有太多理由使用String.format
,但既然是static
,它在性能方面不应该是残酷的,并且它使正则表达式比我在 Java 中能想到的任何其他方式更容易阅读。
它匹配您所有的示例模式(并获得正确的输出,IIRC),包括句子中的版本。您可能遇到的唯一问题是,它会在“让我们在 1 月 1 日见面,好吗?”形式的日期之后立即吃掉逗号,尽管如果写成“让我们在 1 月 1 日见面,好吗?”它不会匹配逗号?” (当我说“匹配逗号”时,我的意思是整个正则表达式将使用逗号,尽管命名的捕获是正确的)。我确实将年份更改为仅匹配四位数。我还将日期更改为仅匹配一位或两位数字。像@MarkusJarderot 一样,我将“september”更改为没有可选的“t”,因为整个后缀是可选的。我尝试编写两个正则表达式,以便添加和删除逻辑块 - 与下面的版本进行比较,需要注意的事情:在某些情况下,两个正则表达式都会匹配(order1 只匹配单个月份,order2 匹配“1st Jan”形式的日期)。您可能想弄清楚在这种情况下如何选择要遵循的表达式。
现在,编写这些正则表达式是为了尽量避免匹配任何不符合所提供格式的日期。我建议修改它们以允许以下形式(# 表示原始列表中的项目):
- 2013 年 1 月 1 日 #
- 2013 年 1 月 1 日 // 注意逗号
- 2013 年 1 月 1 日
- 2013 年 1 月 1 日 #
- 2013 年 1 月 1 日 // 注意逗号前没有空格
- 1月1日#
- 一月 #
Jan //(已经被原始示例支持)
1 月 1 日
- 1月1日#
- 2013 年 1 月 1 日
- 2013 年 1 月 1 日
- 2013 年 1 月 1 日
- 2013 年 1 月 1 日
- 2013 年 1 月 1 日
- 2013 年 1 月 1 日 #
此版本的代码支持上述形式。这也更好:月份已转换为使用所有非捕获模式(因此不会无缘无故地创建额外的捕获),并且我已经根据@MarkusJarderot 的回答删除了围绕整个正则表达式的捕获。日期格式的扩展数量还允许使用较少扭曲的正则表达式。这些表单引入的一个小问题是,现在v1
将尝试将“2013 年 1 月 1 日”形式的日期匹配为“1 月 20 日”,同时v2
正确匹配它们。这与我上面提到的“要小心”的问题相同;您可能想弄清楚如何决定使用哪个正则表达式更好(尝试两者并使用匹配更多日期片段的那个)。
static private String month = "(?<month>jan(?:uary)?|feb(?:ruary)?|mar(?:ch)?|apr(?:il)?|may|jun(?:e)?|jul(?:y)?|aug(?:ust)?|sep(?:t|tember)?|oct(?:ober)?|nov(?:ember)?|dec(?:ember)?)";
static private String suffix = "(?:st|nd|rd|th)";
static private String date = "(?<date>\\d{1,2})";
static private String year = "(?<year>\\d{4})";
// A month name (optionally followed by space followed by a date (optionally
// followed by a suffix)(optionally followed by a comma, possibly with space
// before it)(optionally followed by space followed
// by a year))
static private String v1 = String.format(
"%s(?:\\s+%s%s?(?:\\s*,)?(?:\\s+%s)?)?", month, date, suffix, year);
// A date (optionally followed by a suffix) followed by space followed by a
// month (optionally followed by
// a comma, possibly with space before it) optionally followed by space and
// a year
static private String v2 = String.format(
"%s%s?\\s+%s(?:\\s*,)?(?:\\s+%s)?", date, suffix, month, year);
或者,作为没有 Java 的正则表达式(的输出format
):
(?<month>jan(?:uary)?|feb(?:ruary)?|mar(?:ch)?|apr(?:il)?|may|jun(?:e)?|jul(?:y)?|aug(?:ust)?|sep(?:t|tember)?|oct(?:ober)?|nov(?:ember)?|dec(?:ember)?)(?:\s+(?<date>\d{1,2})(?:st|nd|rd|th)?(?:\s*,)?(?:\s+(?<year>\d{4}))?)?
(?<date>\d{1,2})(?:st|nd|rd|th)?\s+(?<month>jan(?:uary)?|feb(?:ruary)?|mar(?:ch)?|apr(?:il)?|may|jun(?:e)?|jul(?:y)?|aug(?:ust)?|sep(?:t|tember)?|oct(?:ober)?|nov(?:ember)?|dec(?:ember)?)(?:\s*,)?(?:\s+(?<year>\d{4}))?