2013-04-10 2 views
2

У меня есть строки, ["02-03-2013#3rd Party Fuel", "-1#Archived", "2#06-23-2013#Newswire"], которые я хочу разбить на несколько частей. Эти строки имеют префикс с ключами даты и индекса и содержат имя.Рекурсивный RegEx для соответствия ключам и имени

Я разработал RegEx, который соответствует каждой клавише правильно. Однако, если я хочу совместить индексный ключ, ключ даты и имя с махом. Найден только первый ключ. Кажется, рекурсивная группа не работает, как я ожидаю.

private const string INDEX_KEY_REGEX = @"(?<index>-?\d+)"; 
private const string DATE_KEY_REGEX = @"(?<date>(?:0?[1-9]|1[012])-(?:0?[1-9]|[12]\d|3[01])-\d{4})"; 
private const string KEY_SEARCH_REGEX = @"(?<R>(?:^|(?<=#))({0})#(?(R)))(?<name>.*)"; 

private string Name = "2#06-23-2013#Newswire" 
... = Regex.Replace(
    Name, 
    String.Format(KEY_SEARCH_REGEX, INDEX_KEY_REGEX + "|" + DATE_KEY_REGEX), 
    "${index}, ${date}, ${name}" 
); 

// These are the current results for all strings when set into the Name variable. 

// Correct Result: ", 02-03-2013, 3rd Party Fuel" 
// Correct Result: "-1, , Archived" 
// Invalid Result: "2, , 06-23-2013#Newswire" 
// Should be: "2, 06-23-2013, Newswire" 

Острый глаз видит то, что я пропустил?


Окончательное решение, как это было нужно

Оказывается, мне не нужно рекурсивный группу. Я просто нуждался в 0 для многих последовательностей. Вот полный RegEx.

(?:(?:^|(?<=#))(?:(?<index>-?\d+)|(?<date>(?:0?[1-9]|1[012])-(?:0?[1-9]|[12]\d|3[01])-(\d{2}|\d{4})))#)*(?<name>.*) 

И сегментированная RegEx

private const string INDEX_REGEX = @"(?<index>-?\d+)"; 
private const string DATE_REGEX = @"(?<date>(?:0?[1-9]|1[012])-(?:0?[1-9]|[12]\d|3[01])-(\d{2}|\d{4}))"; 
private const string KEY_WRAPPER_REGEX = @"(?:^|(?<=#))(?:{0})#"; 
private const string KEY_SEARCH_REGEX = @"(?:{0})*(?<name>.*)"; 
+0

Он работает для этого тестового примера, если вы удалите тест '^ |'. Какова цель этого? – Bobson

+0

Это должно было гарантировать, что ключи всегда находятся в начале и никогда в конце или не имеют подвешенную строку перед ними. Я буду тестировать без него, но я думаю, что это нарушит указанное требование. Я посмотрю, что я найду. – roydukkey

+0

Итак, при моем тестировании были получены следующие результаты: '2 #, 06-23-2013, Newswire' и' -1 # Archived' (нет совпадений). Так что дальше от желаемого. – roydukkey

ответ

1

хорошо, отдельные regexs распадаются на это:

Индекс: Захват одного положительное или отрицательное число. (-, 0 или 1 повтор, за которым следует одна или несколько цифр)

дата: Указанная дата строка, разделенная -. Никакой надбавки за какой-либо другой формат даты. Обратите внимание, что ведущие «#» и «trailing» # не обрабатываются, он специально фиксирует дату, и только дата

R: начало строки OR #, а затем замена форматирования, чтобы сделать ее одним большим регулярным выражением .. . еще один #, указанный. то условное без false ... и true тоже ничего не делает.

имя: захватить все, что осталось.

конечный результат, скомпилированный в одно регулярное выражение .... два захвата: R и имя. R: (4 части) R-1: Матч либо начало строки или # R-2: Получить ЯВНО (но не оба) Дата или индекс R-3: матч # R-4: Empty Условное выражение name: сопоставить все, что осталось.

Проблема, кажется, что вы не соответствуют как индекс и дату

окончательное редактирование, работа регулярных выражений

медведь со мной, эта вещь неприятная. Вы должны учитывать все 4 возможности, или это не соответствует всем возможным случаям. Я не мог понять, как это обобщить.

(?:(?<index>-?\d+(?!\d-))#(?<date>(?:0?[1-9]|1[012])-(?:0?[1-9]|[12]\d|:3[01])-\d{4})|(?<date>(?:0?[1-9]|1[012])-(?:0?[1-9]|[12]\d|:3[01])-\d{4})#(?<index>-?\d+)|(?!-?\d+#)(?<date>(?:0?[1-9]|1[012])-(?:0?[1-9]|[12]\d|:3[01])-\d{4})|(?<index>-?\d+)(?!#(?:0?[1-9]|1[012])-(?:0?[1-9]|[12]\d|:3[01])-\d{4}))#(?<name>.*) 

уродливый, я знаю. Он имеет 4 начальных условия.

1a) capture <index>#<date> OR 
1b) capture <date>#<index> OR 
1c) capture <index> only, as long as its not followed by a date OR 
1d) capture <date> only, as long as its not preceded by an index 
... 
2) match but ignore # 
3) capture <name> 

работает во всех 4 случаях.

Final: Final Редактировать

Существует способ сделать это, используя 3 regexs, а не только 1, которые могли бы в конечном итоге чище.

//note: index MIGHT be preceeded by, and is ALWAYS followed by, a # 
indexRegex = @"((?=#)?(?<!\d|-)-?\d+(?=#))"; 
//same with date 
dateRegex = @"((?=#)?(?:0?[1-9]|1[012])-(?:0?[1-9]|[12]\d|3[01])-\d{4}(?=#))"; 
//then name 
nameRegex = @"(?:.*#){1,2}(.*)"; 

Запустите их каждый отдельно для замены, чтобы получить отдельные переменные, а затем перестроить строку.

+0

Это выглядит в основном правильно, но '' '' '' '' INDEX_KEY_REGEX' означает, что регулярное выражение будет соответствовать хотя бы одному или нескольким '\ d'. – roydukkey

+0

фактически .... это правильно, его 1 или больше. Мои извинения. Я отредактирую это. – Nevyn

+0

В настоящее время это работает только для индекса с одной цифрой и может испортить дату ... все еще работает над ней. – Nevyn

Смежные вопросы