Другой вариант:
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
, она не должна быть жестокой точки зрения производительности, и это делает регулярное выражение легче читать, чем любым другим способом я мог думать в Ява.
Он соответствует всем вашим образцам (и получает правильный вывод, IIRC), включая версию в предложении. Единственная проблема, которая может возникнуть в том, что она будет есть запятую сразу после даты формы «Встретимся 1 января, хорошо?», Хотя она не будет соответствовать запятой, если она написана «Встретимся 1 января, хорошо ?» (когда я говорю «совпадение с запятой», я имею в виду, что общее регулярное выражение будет принимать запятую, хотя названные записи будут правильными). Я изменил год, чтобы просто сопоставить четыре цифры. Я также изменил дату, чтобы соответствовать только одной или двум цифрам. Как @MarkusJarderot, я изменил «сентябрь», чтобы не иметь необязательного «t», так как весь суффикс является необязательным. Я попытался написать оба регулярных выражения, чтобы логические блоки были добавлены и удалены - сравните с приведенной ниже версией и обратите внимание, как я смог изменить ее, не переписывая все выражение. Кое-что, чтобы быть осторожным: В некоторых случаях оба регулярных выражения будут соответствовать (order1 только соответствует одному месяцу, order2 соответствует дате формы «1st Jan»). Возможно, вам захочется выяснить, как выбрать, какое выражение следует соблюдать в таких случаях.
Теперь эти регулярные выражения были написаны, чтобы избежать совпадения любых дат, не представленных форматов.Я хотел бы предложить изменения их разрешить следующие формы (# указывает пункт в первоначальном списке):
Эта версия кода поддерживает указанные выше формы. Это также лучше: месяцы были преобразованы для использования всех не захватывающих шаблонов (поэтому нет никаких дополнительных захватов, созданных без причины), и я удалил захват вокруг всего регулярного выражения за ответ @ MarkusJarderot. Расширенное количество форматов дат также позволяет использовать меньшее количество искажений. Одна небольшая проблема, введенная этими формами, заключается в том, что теперь v1
постарается сопоставить даты формы «1 янв 2013» как «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}))?
На первый взгляд, это выглядит, как вы правильно сделали с. Вы включили все это, в том числе (\\ s +)?, В другую группу в скобках, за которой следует?, Так что если не соответствует, (\\ s +) не всасывается. Однако вы не сделали то же самое для , или для запятой между и . Попробуйте добавить дополнительный набор круглых скобок (\\ s +)?,? и вокруг (\\ s +)? (? ...) [с? следуя новому набору круглых скобок] и посмотрите, решит ли это вашу проблему. Если нет, я постараюсь взглянуть на нее более внимательно. –
ajb
Чтобы быть ясным, я имею в виду изменение (\\ s +)?,? to ((\\ s +?)), т. е. переместить последнее? вне новой группы, которую вы добавляете. – ajb
Но я замечаю даже, что это пространство засасывается, даже если указан только месяц. Как с «jan», пространство засасывается. – user1411335