How to convert this Backus-Naur form expression to Regex (.Net)?

Expression:

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

The value of the "N" descriptor or one or more of the listed descriptors without repetition.

The best I have:

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

But this does not interfere with repetition.

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

This prevents repetition, but then requires a certain order for the elements, which is also not very good.

Any ideas?

(I'm not sure that the bnf expression itself prohibits repetition, but this is what I need.)

+6
source share
2 answers

Well, you can, but it's ugly:

 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); 

This decision uses negative forecast statements .

+4
source

I am not sure if this is possible even for .net Regex (which is more powerful than a strict definition of "regular language") for this; and in any case, if you have no requirement to use only Regex , there is nothing wrong (in my opinion):

 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; } 

Is this the shortest code that solves the problem? Not. Is it readable and supported? I think so.

(You can write a useful method with the signature int MaxN(params int[] numbers) if you want)

+1
source

Source: https://habr.com/ru/post/915256/


All Articles