2013-10-25 5 views
5

У меня есть следующая строка:Regex вложенных скобок

a,b,c,d.e(f,g,h,i(j,k)),l,m,n 

Знал бы сказать мне, как я мог бы построить регулярное выражение, которое возвращает меня только «первый уровень» круглые скобки что-то вроде этого:

[0] = a,b,c, 
[1] = d.e(f,g,h,i.j(k,l)) 
[2] = m,n 

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

спасибо.

EDIT

Пытаясь улучшить пример ...

Представьте У меня есть эта строка

username,TB_PEOPLE.fields(FirstName,LastName,TB_PHONE.fields(num_phone1, num_phone2)),password 

Моя цель состоит, чтобы превратить строку в динамическом запросе. Тогда поля, которые не начинаются с «TB_», я знаю, что они являются полями главной таблицы, иначе я знаю поля informandos в круглых скобках, связанные с другой таблицей. Но мне трудно получить все поля «первый уровень», так как я могу отделить их от связанных таблиц, я мог бы рекурсивно восстановить оставшиеся поля.

В конце концов, будет иметь что-то вроде:

[0] = username,password 
[1] = TB_PEOPLE.fields(FirstName,LastName,TB_PHONE.fields(num_phone1, num_phone2)) 

Я надеюсь, что я объяснил немного лучше, извините.

+2

Я не понимаю ваш пример. –

+0

Не следует сопоставлять '[1]' be '(f, g, h, i.j (k, l))'? Если нет, можете ли вы объяснить немного больше, пожалуйста? – Vache

+1

из того, что я знаю, Regex не может разобрать вложенные структуры – Jonesopolis

ответ

7

Вы можете использовать это:

(?>\w+\.)?\w+\((?>\((?<DEPTH>)|\)(?<-DEPTH>)|[^()]+)*\)(?(DEPTH)(?!))|\w+ 

С вашего примера вы получите:

0 => username 
1 => TB_PEOPLE.fields(FirstName,LastName,TB_PHONE.fields(num_phone1, num_phone2)) 
2 => password 

Объяснение:

(?>\w+\.)? \w+ \( # the opening parenthesis (with the function name) 
(?>     # open an atomic group 
    \( (?<DEPTH>) # when an opening parenthesis is encountered, 
        # then increment the stack named DEPTH 
    |     # OR 
    \) (?<-DEPTH>) # when a closing parenthesis is encountered, 
        # then decrement the stack named DEPTH 
    |     # OR 
    [^()]+   # content that is not parenthesis 
)*     # close the atomic group, repeat zero or more times 
\)     # the closing parenthesis 
(?(DEPTH)(?!))  # conditional: if the stack named DEPTH is not empty 
        # then fail (ie: parenthesis are not balanced) 

Вы можете попробовать его с этим кодом:

string input = "username,TB_PEOPLE.fields(FirstName,LastName,TB_PHONE.fields(num_phone1, num_phone2)),password"; 
string pattern = @"(?>\w+\.)?\w+\((?>\((?<DEPTH>)|\)(?<-DEPTH>)|[^()]+)*\)(?(DEPTH)(?!))|\w+"; 
MatchCollection matches = Regex.Matches(input, pattern); 
foreach (Match match in matches) 
{ 
    Console.WriteLine(match.Groups[0].Value); 
} 
+0

Привет! Я пытаюсь применить регулярное выражение точно так же, как вы его выразили, но я получаю следующее: [0] => "" [1] => "," [2] => ",", [ 3] => "" Не могли бы рассказать мне, что я забываю делать? Спасибо. – Verner

+0

@Verner: Я добавил пример кода. –

+0

Возможно, вам лучше использовать вложенную количественную группу внутри вашего атома, чтобы предотвратить обратное отслеживание и ускорить распознавание неудачного совпадения. То есть '\ ((?> (?: \ ((? ) | \) (? <-DEPTH>) | [^()] +) *) \)'. Однако, если вы не заботитесь о производительности отказов, тогда это необязательно. (пробелы там только для удобства чтения) – Adrian

0

Если я правильно понял ваш пример, ваш ищете что-то вроде этого:

(?<head>[a-zA-Z._]+\,)*(?<body>[a-zA-Z._]+[(].*[)])(?<tail>.*) 

Для данной строки:

имя пользователя, TB_PEOPLE.fields (FirstName, LastName, TB_PHONE.fields (num_phone1, num_phone2)), пароль

Это выражение будет соответствовать

  • имя пользователя, для группы головы
  • TB_PEOPLE.fields (FirstName, LastName, TB_PHONE.fields (num_phone1, num_phone2)) для группы тела
  • , пароль для группы хвост
0

Предлагаю новую стратегию R2 - сделайте это алгоритмически. Хотя вы можете создать Regex, который в конечном итоге приблизится к тому, что вы просите, он будет грубым недостижимым и будет трудно распространяться, когда вы найдете новые граничные случаи.Я не говорю C#, но это псевдо-код должен получить Вас на правильном пути:

function parenthetical_depth(some_string): 
    open = count '(' in some_string 
    close = count ')' in some_string 
    return open - close 

function smart_split(some_string): 
    bits = split some_string on ',' 
    new_bits = empty list 
    bit = empty string 
    while bits has next: 
     bit = fetch next from bits 
     while parenthetical_depth(bit) != 0: 
      bit = bit + ',' + fetch next from bits 
     place bit into new_bits 
    return new_bits 

Это самый простой способ понять это, алгоритм в настоящее время O(n^2) - есть оптимизация для внутреннего контура, чтобы сделать она O(n) (за исключением струнного копирования, который является своего рода худшей части этого):

depth = parenthetical_depth(bit) 
while depth != 0: 
    nbit = fetch next from bits 
    depth = depth + parenthetical_depth(nbit) 
    bit = bit + ',' + nbit 

строка копирование может быть сделано более эффективным с умным использованием буферов и размера буфера, за счет пространства но я не думаю, что C# дает вам этот уровень контроля изначально.

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