2012-05-09 37 views
6

Khái niệm là:Làm thế nào tôi có thể chuyển đổi biểu thức Biểu mẫu Backus – Naur này thành một Regex (.Net)?

N | (1 { A | B | C | D | E1 | E2 | E3 }) 

Nghĩa là mô tả "N" hoặc một hoặc nhiều trong những mô tả liệt kê mà không lặp lại.

Điều tốt nhất tôi đã có là:

@"^(N|(A|B|C|D|E1|E2|E3){1,})$" 

Nhưng điều đó không ngăn cản sự lặp lại.

@"^(N|(A{0,1}B{0,1}...)$" 

Điều đó ngăn chặn sự lặp lại nhưng sau đó yêu cầu thứ tự cụ thể cho các thành phần, điều này cũng không thực sự ổn.

Bất kỳ ý tưởng nào?

(Tôi không thực sự chắc chắn rằng biểu thức BNF bản thân không cho phép lặp lại, nhưng đó là những gì tôi cần.)

+0

http://kore-nordmann.de/blog/do_NOT_parse_using_regexp.html Sử dụng cụm từ thông dụng để nhận dạng từ chứ không phải cấu trúc. –

+0

Tôi đoán là có ý nghĩa. Nhưng tôi sẽ sử dụng cái gì để nhận ra cấu trúc này? @DavidBrabant Nó sẽ được sử dụng để xác thực đầu vào của biểu mẫu được đề cập. – Daniel

+0

Hay PCRE là phương pháp mà bạn đang đề xuất? – Daniel

Trả lời

4

Vâng, bạn có thể, nhưng nó không phải là khá:

Regex regexObj = new Regex(
    @"^   # Start of string 
    (?:   # Either match... 
    N   # N 
    |    # or... 
    (?:   # Match one of the following: 
     A(?!.*A) # A unless followed somewhere later by another A 
    |   # or 
     B(?!.*B) # B unless... 
    |   # etc. etc. 
     C(?!.*C) 
    | 
     D(?!.*D) 
    | 
     E1(?!.*E1) 
    | 
     E2(?!.*E2) 
    | 
     E3(?!.*E3) 
    )+   # one or more times 
    )    # End of alternation 
    $    # End of string", 
    RegexOptions.IgnorePatternWhitespace); 

giải pháp này sử dụng negative lookahead assertions.

+0

Rất tốt, cảm ơn bạn! – Daniel

+0

Chỉ là một câu hỏi @Tim. Hàm '?:' Có ​​chức năng gì? Có vẻ như nó đang hoạt động mà không có hai người đó. – Daniel

+0

@Daniel: Sự khác biệt duy nhất là '(...)' là một nhóm * capturing *, có nghĩa là công cụ regex lưu trữ bất kỳ thứ gì được khớp trong nhóm đó trong một backreference mà bạn có thể tham khảo sau này. Nếu bạn không cần phải làm điều đó, '(?: ...)' hoạt động giống nhau, nhưng không lưu trữ phần đó của trận đấu. Do đó, chúng hiệu quả hơn một chút. –

1

Tôi không chắc nó có thể ngay cả đối với một .net Regex (đó là mạnh mẽ hơn định nghĩa nghiêm ngặt về 'ngôn ngữ thông thường') để làm điều này; và dù sao, trừ khi bạn có nhu cầu sử dụng chỉ một Regex, không có gì sai (để tâm trí của tôi) với:

bool IsValid(string input) 
{ 
    var Ns = input.Count(c => c == 'N'); 
    var As = input.Count(c => c == 'A'); 
    // etc 
    var E1s = Regex.Matches(input, "E1").Count 
    // etc 

    var maxDescriptorCount = (new[] { As, ... ,E1s, ... }).Max(); 

    var isValid = 
     ((Ns == 1) && (maxDescriptorCount == 0)) 
     || 
     ((Ns == 0) && (maxDescriptorCount == 1)) 
     ; 

    return isValid; 
} 

Có mã ngắn nhất có thể giải quyết vấn đề? Không. Có thể đọc và duy trì được không? Tôi nghĩ vậy.

(Bạn có thể viết một phương pháp hữu ích với chữ ký int MaxN(params int[] numbers) nếu bạn muốn)

Các vấn đề liên quan