2013-10-25 61 views
5

Ben şu dize:Regex İç içe parantezler

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

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

Ben sadece böyle parantezler şeyin "ilk düzeyi" beni döndüren bir düzenli ifade inşa edebileceğini nasıl söyle bilir mi

Amaç, aynı dizine sahip olan bölümün gelecekteki işlemek için iç içe parantez içinde tutulmasıdır.

Teşekkür ederiz.

DÜZENLEME örneğini geliştirmek için çalışılıyor

...

Ben

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

Amacım dinamik sorgu bir dize açmaktır bu dizesi vardır düşünün. Daha sonra "TB_" ile başlamayan alanlar, bunların ana tablonun alanları olduğunu biliyorum, aksi halde alanları parantez içinde biliyorum, başka bir tabloyla ilişkilidir. Ama tüm tabloları "birinci seviye" alma konusunda zorluk çekiyorum çünkü onları ilgili tablolardan ayırabiliyorum, geri kalan alanları tekrar tekrar ele geçirebilirim. Özür, biraz daha iyi izah umut

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

: Sonunda

, gibi bir şey olurdu. Verilen dize için

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

: Ben doğru örnek anlasalardı

+2

Örneğini anlamıyorum. –

+0

Eşleşmemeli [1] 'be' (f, g, h, i.j (k, l)) '? Değilse, biraz daha açıklayabilir misiniz lütfen? Bildiğim kadarıyla – Vache

+1

, Regex yuvalanmış yapıları ayrıştıramıyor – Jonesopolis

cevap

7

Bunu kullanabilirsiniz: Örneğin ile

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

edinmeniz:

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

Açıklama:

(?>\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) 

Bu kodla deneyebilirsiniz:

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

Merhaba! Regex'i tam olarak koyduğunuz gibi kullanmaya çalışıyorum, ancak şu an sahip olduğum getiri: [0] => "" [1] => "," [2] => ",", [ 3] => "" Bana ne yapmayı unuttuğumu söyleyebilir misin? Teşekkür ederiz. – Verner

+0

@Verner: Bir örnek kod ekledim. –

+0

Geri dönüşü engellemek ve başarısız bir eşleşmenin tanınmasını hızlandırmak için atomik içinizdeki iç içe geçmiş bir grup kullanarak daha iyi olabilirsiniz. Yani '\ ((?> (?: \ ((? ) | \) (? <-DEPTH>) | [^()] +) *) \)'. Ancak, başarısızlık performansına önem vermiyorsanız, o zaman gerekli değildir. (sadece okunabilirlik için boşluklar var) – Adrian

0

, senin böyle bir şey arıyor

kullanıcı adı, TB_PEOPLE.fields (ad, soyadı, TB_PHONE.fields (num_phone1, num_phone2)), şifre

Bu ifade maç olacak

  • adı grup baş grubu grup gövde
  • , şifre için
  • TB_PEOPLE.fields (ad, soyadı, TB_PHONE.fields (num_phone1, num_phone2)) için Kuyruk
0

Yeni bir strateji öneririm, R2 - algoritmik olarak yapın. Nihayetinde sorduğun soruya yaklaşacak bir Regex oluşturabilirken, büyük ihtimalle son derece ulaşılabilir olmayacak ve yeni kenar durumları bulduğunda uzamanız zor olacak.C# konuşan yok, ama bu sahte kod doğru yolda almalısınız:

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 

Bunu anlamak için de en kolay yoludur, algoritma şu anda O(n^2) olduğunu - iç döngü yapmak için bir optimizasyon var Bu O(n) (bu en kötü bölüm türüdür dize kopyalama haricinde,):

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

dize kopyalama alan pahasına, tamponlar ve tampon boyutunun akıllı kullanımı ile daha etkin bir hale getirilebilir Verimlilik, ama C# 'nin size doğal olarak bu kontrol seviyesini verdiğini sanmıyorum.