2013-07-03 3 views
3

Я хочу зафиксировать даты, указанные в алфавитном порядке. Может быть, одна из форм ниже 1Игнорирование пространства после первой группы захвата, если группа после того, как ее не захватили

  • Jan 2013
  • 1 января 2013
  • 1 января
  • 1 января
  • 1 января 2013
  • января

Кроме того, они будут встречаться в предложении. Например,

«Можем ли мы встретиться где-нибудь в январе днем».

Я использую следующие регулярные выражения в Java

((?<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+)?(st|nd|rd|th))?(\\s+)?,?(\\s+)?(?<year>(20)\\d\\d)?) 

((?<date>\\d+)?(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+)?,?(?<year>(19|20)\\d\\d)?) 

мне нужно указать точное положение маркеров в строке после захвата регулярных выражений.

Когда я смотрю на индекс, возвращаемый Matcher.end() Кажется, мое выражение также захватывает пространство после января. Я хочу захватить выражения типа «1 января», но только тогда, когда возможно совпадение следующей группы захвата.

Можно ли изменить регулярные выражения выше, чтобы сделать это?

+1

На первый взгляд, это выглядит, как вы правильно сделали с . Вы включили все это, в том числе (\\ s +)?, В другую группу в скобках, за которой следует?, Так что если не соответствует, (\\ s +) не всасывается. Однако вы не сделали то же самое для , или для запятой между и . Попробуйте добавить дополнительный набор круглых скобок (\\ s +)?,? и вокруг (\\ s +)? (? ...) [с? следуя новому набору круглых скобок] и посмотрите, решит ли это вашу проблему. Если нет, я постараюсь взглянуть на нее более внимательно. – ajb

+0

Чтобы быть ясным, я имею в виду изменение (\\ s +)?,? to ((\\ s +?)), т. е. переместить последнее? вне новой группы, которую вы добавляете. – ajb

+0

Но я замечаю даже, что это пространство засасывается, даже если указан только месяц. Как с «jan», пространство засасывается. – user1411335

ответ

2

Расширение шаблон для более читабельности:

(
    (?<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+)? 
     (st|nd|rd|th) 
    )? 
    (\\s+)? 
    ,? 
    (\\s+)? 
    (?<year>(20)\\d\\d)? 
) 

Промежутки до года может соответствовать даже когда год не делает. Кроме того, суффикс даты может совпадать, даже если дата не указана.

очистки и закрепления рисунка я получил это:

\\b 
(?<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+) 
    (st|nd|rd|th)? 
)? 
(
    \\s* 
    ,? 
    \\s* 
    (?<year>(19|20)\\d\\d) 
)? 
\\b 

Я удалил внешнюю группу, так как вы получите, что в группе 0 в любом случае. t? в sep(t?|tember)? было изменено на t. Все (\\s+)? было изменено на эквивалент \\s*. Я переместил ? от (?<date>\\d+)? до (st|nd|rd|th). Я завернул год в группу и переместил ? от (?<year>20\\d\\d). Я добавил слова-границы (\\b), чтобы он не начинался и не заканчивался посредине слова.

В одной строке:

\\b(?<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+)(st|nd|rd|th)?)?(\\s*,?\\s*(?<year>(19|20)\\d\\d))?\\b 

Комбинируя его с вторым рисунком:

\\b 
(
    (?<month1> 
     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* 
     (?<date1>\\d+) 
     (st|nd|rd|th)? 
    )? 
    | 
    (?<date2>\\d+) 
    (st|nd|rd|th)? 
    \\s* 
    (?<month2> 
     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>(19|20)\\d\\d) 
)? 
\\b 

В одной строке:

\\b((?<month1>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*(?<date1>\\d+)(st|nd|rd|th)?)?|(?<date2>\\d+)(st|nd|rd|th)?\\s*(?<month2>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>(19|20)\\d\\d))?\\b 
+0

Благодарим за ответ – user1411335

1

Другой вариант:

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»). Возможно, вам захочется выяснить, как выбрать, какое выражение следует соблюдать в таких случаях.

Теперь эти регулярные выражения были написаны, чтобы избежать совпадения любых дат, не представленных форматов.Я хотел бы предложить изменения их разрешить следующие формы (# указывает пункт в первоначальном списке):

  • Jan 1st 2013 #
  • 1 января 2013 г. // Примечание запятая
  • 1 января 2013
  • 1 января 2013 #
  • 1 января 2013 // Примечание нет места перед запятой
  • Jan 1 #
  • января #
  • Jan // (уже поддерживается исходного примера)

  • 1 янв

  • 1 января #
  • 1 января 2013
  • 1 января 2013
  • 1 января 2013
  • первый Jan 2013
  • 1 янв, 2013
  • 1 янв, 2013 год #

Эта версия кода поддерживает указанные выше формы. Это также лучше: месяцы были преобразованы для использования всех не захватывающих шаблонов (поэтому нет никаких дополнительных захватов, созданных без причины), и я удалил захват вокруг всего регулярного выражения за ответ @ 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}))? 
+0

Благодарим за ответ. Я не смогу сделать это в коде, поскольку я должен держать их в конфигурации. Но спасибо, что нашли время, чтобы указать на предостережения. – user1411335

+0

@ user1411335 Я добавил регулярные выражения без кода Java, если это было бы полезно. Кроме того, я исправил блоки кода - они не отображались правильно. – andyg0808