У меня есть это регулярное выражение .NET:
^(?<prefix>("[^"]*"))\s(?<attrgroup>(\([^\)]*\)))\s(?<suffix>("[^"]*"))$
Он правильно соответствует следующим строкам:
"some prefix" ("attribute 1" "value 1") "some suffix"
"some prefix" ("attribute 1" "value 1" "attribute 2" "value 2") "some suffix"
Не получается ...
"some prefix" ("attribute 1" "value (fail) 1") "some suffix"
... из-за правильного символа после слова "fail".
Как я могу изменить свое регулярное выражение так, чтобы группа соответствия attrgroup содержала в конечном итоге "("attribute 1" "value (fail) 1")"? Я смотрел на это слишком долго, и мне нужен свежий взгляд. Спасибо!
Редактировать:attrgroup никогда не будет содержать ничего, кроме пар строк в двойных кавычках.
Хороший вопрос! Ответ - нет, и они всегда идут парами.





^(?<prefix>"[^"]*")\s+(?<attrgroup>\(.*\))\s+(?<suffix>"[^"]*")$
исправил это для меня.
Я удалил посторонние безымянные группы и упростил (до «любого символа») группу атрибутов.
Стоит инвестировать в очень RegexBuddy от JG Soft.
Обновлено: это не будет проверять группу атрибутов как пары строк в кавычках, но это должно / может быть выполнено на отдельном этапе регулярного выражения / проверки.
Решение Hometoasts - хорошее решение, хотя, как и любое либеральное регулярное выражение, его следует использовать только для извлечения данных из источников, у вас есть разумная уверенность, что они правильно сформированы, а не для проверки.
Не обращая внимания на специфику этого регулярного выражения, я бы рекомендовал использовать инструмент Regex для создания, тестирования и проверки ваших регулярных выражений. Для чего-либо нетривиального или выражений, которые вам может понадобиться поддерживать / обновлять, инструменты такого рода необходимы.
Проверить...
Тренер Regex - Написано на Лиспе, немного старше, но я действительно предпочитаю этот другим.
Rad Software Regex Designer - .NET и возможно более "современный". Кому-то это может понравиться.
моя непроверенная догадка:
^(?<prefix>("[^"]*"))\s(?<attrgroup>(\(("[^"]*")(\s("[^"]*")*)**\)))\s(?<suffix>("[^"]*"))$
настоящим я заменил
[^\)]*
с
("[^"]*")(\s("[^"]*")*)*
Я предположил, что все в скобках заключено в двойные кавычки или является пробелом.
Если вы хотите узнать, как я это придумал, прочтите Освоение регулярных выражений.
пс. если я прав, тогда это также будет проверять группу атрибутов как пары строк в кавычках.
Я предлагаю использовать синтаксический анализатор, способный обрабатывать такие структуры. Регулярное выражение не работает, и это правильно, поскольку язык, который вы пытаетесь разобрать, не выглядит правильным - по крайней мере, из примеров, приведенных выше. Всякий раз, когда вам нужно распознать вложенность, регулярные выражения либо не сработают, либо превратятся в сложных зверей, подобных приведенному выше. Даже если язык регулярный, это регулярное выражение кажется мне слишком сложным. Я бы предпочел использовать что-то вроде этого:
def parse_String(string):
index = skip_spaces(string, 0)
index, prefix = read_prefix(string, index)
index = skip_spaces(string, index)
index, attrgroup = read_attrgroup(string, index)
index = skip_spaces(string, index)
index, suffix = read_suffix(string, index)
return prefix, attrgroup, suffix
def read_prefix(string, start_index):
return read_quoted_string(string, start_index)
def read_attrgroup(string, start_index):
end_index, content = read_paren(string, start_index)
index = skip_spaces(content, 0)
index, first_entry = read_quoted_string(content, index)
index = skip_spaces(content, index)
index, second_entry = read_quoted_string(content, index)
return end_index, (first_entry, second_entry)
def read_suffix(string, start_index):
return read_quoted_string(string, start_index)
def read_paren(string, start_index):
return read_delimited_string(string, start_index, '(', ')')
def read_quoted_string(string, start_index):
return read_delimited_string(string, start_index, '"', '"')
def read_delimited_string(string, starting_index, start_limiter, end_limiter):
assert string[starting_index] == start_limiter, (start_limiter
+"! = "
+string[starting_index])
current_index = starting_index+1
content = ""
while(string[current_index] != end_limiter):
content += string[current_index]
current_index += 1
assert string[current_index] == end_limiter
return current_index+1, content
def skip_spaces(string, index):
while string[index] == " ":
index += 1
return index
да, это больше кода, и да, судя по необработанному количеству ключей, это заняло больше времени. Однако - по крайней мере, для меня - мое решение гораздо легче проверить. Это еще больше возрастет, если вы удалите связку строк и индексов, переместив все это в класс, который анализирует такие строки в своем конструкторе. Кроме того, легко сделать неявный пропуск пробелов (используя некоторый волшебный метод next-char, который просто пропускает символы до тех пор, пока не появится непробел, если только он не находится в каком-либо режиме без пропуска из-за строк. Этот режим может быть установлен в функция-разделитель, например). Это превратит parse_string в:
def parse_string(string):
prefix = read_prefix()
attrgroup = read_attr_group()
suffix = read_suffix()
return prefix, attrgroup, suffix.
Кроме того, эти функции могут быть легко расширены для охвата более сложных выражений. Произвольно вложенные группы attrgroups? изменение одной строчки кода. Вложенные паренсы? немного больше работы, но нет реальных проблем.
А теперь прошу вас поджечь и проголосовать против меня за то, что я еретик регулярных выражений и защитник парсеров. > :)
PS: да, этот код не тестировался. насколько я знаю, там есть 3 опечатки, которых я не видел.
Согласно вашей входной спецификации,
attrgroupкогда-либо содержит что-либо, кроме строк в двойных кавычках?