регулярное выражение: использование окружающих скобок в качестве разделителей при игнорировании любых внутренних скобок - PullRequest
0 голосов
/ 18 ноября 2009

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

(?'field'F[0-9]{1,4})(?'term'\(.*?\))(?'operator'_(OR|NOT|AND)_)?

В следующих примерах мне нужно получить группы после комментария, но в 3-м примере я получаю ((brackets) вместо ((brackets)are valid).

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

C:\Temp\[DB_3][DT_2][F30(green)].vsl // F30 (green)
C:\Temp\[DB_3][DT_2][F21(red)_OR_F21(blue)_NOT_F21(pink)].vsl // F21 (red) _OR_ OR
C:\Temp\[DB_3][DT_2][F21((brackets)are valid)].vsl // F21 ((brackets)are valid)
C:\Temp\[DB_3][DT_2][F21(any old brackets)))))are valid)].vsl // F21 (any old brackets)))))are valid)
C:\Temp\[DB_3][DT_2][F21(brackets))))))_OR_F21(blue)].vsl // F21 (brackets)))))) _OR_ OR

Спасибо


ОБНОВЛЕНИЕ: я использую RegExr для экспериментов, а затем реализую в C # так:

Regex r = new Regex(pattern, RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);

foreach(Match m in r.Matches(foo))
{
    //etc
}

ОБНОВЛЕНИЕ 2: мне не нужно сопоставлять скобки. Внутри одного набора скобок могут быть любые данные, мне просто нужно, чтобы они заканчивались внешними скобками.


ОБНОВЛЕНИЕ 3:

Еще одна попытка, которая работает с дополнительными скобками (пример 3 и 4), но по-прежнему не позволяет выделить дополнительные термины (пример 5), но, к сожалению, включает в себя завершающий ] в группе. Как я могу заставить его искать (но не включать) либо )_, либо )] в качестве разделителя, но просто включить скобку?

(?'field'F[0-9]{1,4})(?'term'\(.*?\)[\]])(?'operator'_(OR|NOT|AND)_)?

Окончательное обновление: я решил, что пытаться разобрать этот глупый формат не стоит, поэтому я собираюсь отказаться от его поддержки и сделать что-то более продуктивное с моим временем. Спасибо всем за помощь, теперь я видел свет!

Ответы [ 5 ]

2 голосов
/ 18 ноября 2009

вот мои другие результаты теста в python

x="""C:\Temp\[DB_3][DT_2][F30(green)].vsl // F30 (green)
C:\Temp\[DB_3][DT_2][F21(red)_OR_F21(blue)_NOT_F21(pink)].vsl // F21 (red) _OR_ OR
C:\Temp\[DB_3][DT_2][F21((brackets)are valid)].vsl // F21 ((brackets)are valid)
C:\Temp\[DB_3][DT_2][F21(any old brackets)))))are valid)].vsl // F21 (any old brackets)))))are valid)
C:\Temp\[DB_3][DT_2][F21(brackets))))))_OR_F21(blue)].vsl // F21 (brackets)))))) _OR_ OR"""
x=re.sub("//.*","",x)
x=re.sub("(_(OR|NOT|AND)_).*?]"," \\1 \\2]",x)
x=re.findall("(?:F[0-9]{1,4}\(.*\).*(?=]))",x)
for x in x:print x

это дает

F30(green)
F21(red) _OR_ OR
F21((brackets)are valid)
F21(any old brackets)))))are valid)
F21(brackets)))))) _OR_ OR

Это будет соответствовать вашему ожидаемому результату?

2 голосов
/ 18 ноября 2009

Хм, это обычно невозможно с большинством двигателей регулярных выражений. Хотя это возможно в Perl:

PerlMonks

Используя рекурсивное регулярное выражение:

use strict;
use warnings;

my $textInner =
  '(outer(inner(most "this (shouldn\'t match)" inner)))';
my $innerRe;
my $idx=0;
my(@match);

$innerRe = qr/
                \(
                (
                   (?:
                      [^()"]+
                   |
                      "[^"]*"
                   |
                      (??{$innerRe})
                   )*
                )
                \)(?{$match[$idx++]=$1;})
             /sx;

$textInner =~ /^$innerRe/g;

print "inner: $match[0]\n";

Это также возможно сделать в большинстве движков регулярных выражений при условии, что вы хотите сделать это с фиксированной глубиной вложенности скобок. Некоторое время назад я написал что-то на языке java, в котором было бы построено регулярное выражение, которое соответствовало бы скобкам глубиной до 6.

Вот моя Java-функция для создания регулярного выражения:

public static String generateParensMatchStr(int depth, char openParen, char closeParen)
{
    if (depth == 0)
        return ".*?";
    else
        return "(?:\\" + openParen + generateParensMatchStr(depth - 1, openParen, closeParen) + "\\" +closeParen + "|.*?)+?";
}
2 голосов
/ 18 ноября 2009

Соответствие вложенных скобок с регулярным выражением равно a) невозможно * или b) приводит к тому, что регулярное выражение не поддерживается.

Если вы просто пытаетесь сопоставить первый ( до последнего ) (не проверяя, правильно ли совпадают открывающая и закрывающая скобки), просто удалите ? после .*?.

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

1 голос
/ 18 ноября 2009

Попробуйте это

/(F[0-9]{1,4})(\([^_\]]+\))(?:_(OR|NOT|AND)_)?/

протестировано с PHP, похоже, дает ожидаемые результаты (если строки внутри круглых скобок не содержат _ или ]).

1 голос
/ 18 ноября 2009
re.findall("((?:F[0-9]{1,4}\(.*\))(?:_(?:OR|NOT|AND)_)?)+?",YOURTEXT)

Гоц

['F30(green)', 'F21(red)_OR_F21(blue)_NOT_F21(pink)', 'F21((brackets)are valid)', 'F21(any old brackets)))))are valid)', 'F21(brackets))))))_OR_F21(blue)']

в python, как вы думаете?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...