Regex to validate logical && || operators in string - c#

I am trying to create a Regex expression to validate logical && || string combonation and its corresponding opening and closing () brackets.
I have been messing with the Regex hieroglyphic pattern but can't seem to get it working correctly, mainly due to my complete lack of understanding of the Regex pattern.
After several hours of StackOverflow and google this is what I have so far, I feel I am close.
private void ValidationTest()
{
string hieroglyphics = #"^(?=^[^()]*\((?>[^()]+|\((?<DEPTH>)|\)(?<-DEPTH>))*(?(DEPTH)(?!))\)[^()]*$)[(]*\d+[)]*(\s+(&&|\|\|)\s+[(]*\d+[)]*)*$";
var tests = new List<string>
{
// Working
"(1 && 2)",
"((1 && 2) && (3 || 4))",
"((1 && 2) && (3 || 4) || ((1 && 2) && (3 || 4)))",
// Not working
"(Stack && Overflow)"
};
if (tests.All(test => Regex.IsMatch(test, hieroglyphics)))
{
MessageBox.Show("Woohoo!!");
}
}
So the main issue with what I have so far is if ther are no brackets 1 && 2 it wont validate, same with (1 && 2) && (3 || 4).
Also it seems to ignore words alltogeter (Stack && Overflow)
Examples of some strings I am tring to validate.
"IsRecording && IsPlaying"
"IsVisible && (IsPlaying && (IsMusic || IsRadio))"
There is also some keywords that contain brakets that could mess things up
Example:
"IsWindowVisible(2) && (IsControlVisible(22) && IsControlFocused(100))"
Edit:
As it is now this expression works fine validating the kind of complexity I need, however the only real issue I have is that its nubers only.
Complex example that validates fine with this Regex
"((1 && 2) && (3 || 4) || ((1 && 2) && (3 || 4)))"
A simple string 1 && 2 wont validate without brakets, but I dont mind adding brackest to these.
all I need is to add support for words instead of just numbers, this will be a fixed list of words if that helps.
If someone can spot the error or point me in a better direction would be awesome
Thanks
Edit:
Answer by mellamokb worked perfect. It seems the trouble was the d+ needed to be 0-9a-zA-Z()
Here is the pattern incase it usefull for anyone else.
string hieroglyphics = #"^(?=^[^()]*(?>[^()]+|\((?<DEPTH>)|\)(?<-DEPTH>))*(?(DEPTH)(?!))[^()]*$)[(]*[0-9a-zA-Z()]+[)]*(\s+(&&|\|\|)\s+[(]*[0-9a-zA-Z()]+[)]*)*$";
it validates exactly what I need
Examples:
"IsPlayer(Video) && Player(Playing)",
"((IsPlayer(Video) && (Player(Playing) && ControlIsVisible(34))) || (IsPlayer(Video) && (Player(Playing) && ControlIsVisible(34)))) && ControlIsFocused(22)"

I think the reason you are not able to validate expressions without a wrapping () is the wrapping parentheses in your core nesting logic. If you take out the following parentheses I note below, then the other two non-wrapped expressions validate:
^(?=^[^()]*\((?>[^()]+|\((?<DEPTH>)|\)(?<-DEPTH>))*(?(DEPTH)(?!))\)[^()]*$...
^^ remove this remove this ^^
Then in order to allow expressions that are not just numerical, you need to replace your restrictive \d with a more liberal definition of what you want to validate, say, [0-9a-zA-Z]:
...[(]*\d+[)]*(\s+(&&|\|\|)\s+[(]*\d+[)]*)*$
^^ change these expression ^^
So it would become:
...[(]*[0-9a-zA-Z]+[)]*(\s+(&&|\|\|)\s+[(]*[0-9a-zA-Z]+[)]*)*$
Demo: http://ideone.com/jwkcpL

Related

Best way to check several conditions on a Textbox.Text

I'm done with my current project and currently trying to improve the code itself.
In the app I developped, when the user clicks the "print" button, the different text in the textboxes are verified for things like is it null or empty ? is it numeric ?
My problem is that I end up with monster lines of code like
if (!String.IsNullOrEmpty(textBoxNbPieces.Text) && !String.IsNullOrEmpty(textBoxNbLotTrempe.Text) && !int.TryParse(textBoxNbPieces.Text, out numero) && !int.TryParse(textBoxNbLotTrempe.Text, out numero))
{
if (int.Parse(textBoxNbPieces.Text) < int.Parse(textBoxNbLotTrempe.Text))
{
erreur++;
}
}
How could I avoid that ?
You dont need to check IsNullOrEmpty and also int.TryParse, the latter includes the former.
bool valid = int.TryParse(textBoxNbPieces.Text, out int pieces)
&& int.TryParse(textBoxNbLotTrempe.Text, out int trempe)
&& pieces >= trempe;
if(!valid) erreur++;
[disclaimer: C#7 syntax]

if (a or b) and c statement

I'm having difficulty with a multiple option if statement.
Version 1 matches all without considering the && .contains("up")
if (
|| drow["ifName"].ToString().ToLower().Contains("vlan")
|| drow["ifName"].ToString().ToLower().Contains("st0")
|| drow["ifName"].ToString().ToLower().Contains("ge-0")
&& drow["ifStatus"].ToString().ToLower().Contains("up")
)
Version 2 matches none.
if ( (
|| drow["ifName"].ToString().ToLower().Contains("vlan")
|| drow["ifName"].ToString().ToLower().Contains("st0")
|| drow["ifName"].ToString().ToLower().Contains("ge-0")
)
&& drow["ifStatus"].ToString().ToLower().Contains("up")
Something I am missing?
Table looks basically like
ifName | ifStatus
vlan.0 | up
st0.1 | up
pp0.0 | up
ge-0/0/0 | down
EDIT:
So the goal is to match only rows that have ifStatus = UP, also changed table to clarify a real example.
What is your intended parse? logical OR (||) and logical AND (&&) are both left-associative and have different operator precedences:
http://msdn.microsoft.com/en-us/library/aa691323(v=vs.71).aspx
Logical AND binds more tightly than does logical OR, so, an expression like
A || B || C && D
parses as if it were written
A || B || ( C && D )
If that is your intent, you're good. If not, you'll need to add parentheses as needed to get the desired parse. My suspicion is that your intended parse is more like:
(A || B || C ) && D
But that is not how your original test parses.
As a good general rule, if you're mixing ANDs and ORs in a logical expression, always use parentheses to indicate your intent. Misunderstanding operator precedence in logical expressions is a major source of bugs.
This may not fix your problem, but it should make it easier to see what you're doing, as well as make the list more maintainable:
var matchNames = new[] {"a", "b", "c", "vlan.10"};
if (drow["ifStatus"].ToString().ToLower().Contains("up") //check up first, because it's cheaper
&& matchNames.Any(m => drow["ifName"].ToString().ToLower().Contains(m) )
{
//...
}
You can use linq to do this, for sample, add this namespace:
using System.Linq;
and try this:
string[] items = new[] { "vlan.10", "a", "b", "c" };
if (drop["IfStatus"].ToString().IndexIf("up", StringComparison.OrdinalIgnoreCase) > -1 &&
items.Any(x => drop["IfName"].ToString().IndexOf(x, StringComparison.OrdinalIgnoreCase) > -1)
{
// true...
}
Read about the Turkey Test, it shows why is important using the IgnoreCase method to compare instead Contains.
Using a regex here can simplify the logic.
if((Regex.IsMatch(drow["ifName"].ToString().ToLower(), "[abc]"))
&& (Regex.IsMatch(drow["ifStatus"].ToString().ToLower(), "up")))
{
}
in first case: it produce true if any one of the expression (OR Expression or AND Expression)evaluates to true.
Note : it is similar to if(A || B || C || D && E)
so if any OR Expressionin (A,B,C) evalutes to true or Expression D and E evaluates to true it becomes true.
in second case : it produce true if any one of the OR expressions is true and AND Expression drow["ifStatus"].ToString().ToLower().Contains("up") also must be true as you are using parenthesis pair.
Note : it is similar to if( (A || B || C || D) && (E) )
so if any one of the OR Expression(A,B,C,D) should evaluate to true and also AND expression E must be true to produce the result true.
Try This:
String name=drow["ifName"].ToString().ToLower();
Sting status=drow["ifStatus"].ToString().ToLower();
if ( (name.Contains("vlan.10") || name.Contains("a") || name.Contains("b")
|| name.Contains("c")) && (status.Contains("up")))

Does .net stop checking the rest of an IF statement if you use an and/or ( || / && )?

say you have something like:
int num = 0
then you do
if(num > 5 || num < 4)
{
...
}
it checks both, but what if you do
if(num < 4 || num > 5)
{
...
}
does it only check the 1st statement?
same as:
if(num > 5 && num == 0)
{
...
}
it should stop after failing the 1st and... right?
This is called boolean short-circuit evaluation and (although [citation-needed]) yes, C# and VB.NET have it (thanks #Lasse for the correction).
In C#, || and && are the short-circuited versions of | and &, respectively
.
Yes, this feature is called short circuit evaluation. If the first argument to the AND operator (&&) is false, then the entire expression will be false. Similarly with OR (||) if the first operand in true, the entire thing is true.
This feature is useful if you want to write the code similar to:
if(a != null && a.isValid())
... Code ...
This way you are not going to get an exception if a is null.
MSDN documentation http://msdn.microsoft.com/en-us/library/2a723cdk%28v=vs.71%29.aspx
If you do it right, yes. Take a look here: http://devpinoy.org/blogs/nocampo/archive/2007/09/28/short-circuit-evaluation-in-c-and-vb-net.aspx
EDIT: To clarify; C# yes, VB.NET if you use the right keywords.

Concat string in IsNullOrEmpty parameter

I was looking at a piece of code I wrote in C#:
if(string.IsNullOrEmpty(param1) && string.IsNullOrEmpty(param2) && string.IsNullOrEmpty(param3))
{
// do stuff
}
and decided to make it more readable/concise
if(string.IsNullOrEmpty(param1+param2+param3))
{
// do stuff
}
But looking at it I can't help but cringe. What are your thoughts on this? Have you ever done something like this and do you use it whenever applicable.
Note: The code previous to this line would manipulate a collection by adding specific items depending on if the a param (param1,param2,param3) is NOT empty. This if statement is meant for validation/error handeling.
Personally I prefer the former over the latter. To me the intent is more explicit -- checking if all parameters are null/empty.
The second also hides the fact it does handle nulls. Null strings are odd. Jason Williams above, for example, didn't relise that it does in fact work.
Maybe write it something like this, which is a bit more readable:
bool paramsAreInvalid =
string.IsNullOrEmpty(param1)
&& string.IsNullOrEmpty(param2)
&& string.IsNullOrEmpty(param3);
if (paramsAreInvalid)
{
// do stuff
}
It's a small thing, but I think a minor reformatting of your original results in improved readability and makes the intent of the code about as crystal clear as can be:
if ( string.IsNullOrEmpty(param1) &&
string.IsNullOrEmpty(param2) &&
string.IsNullOrEmpty(param3) )
{
// do stuff
}
Consider this similar set of examples:
if ( c == 's' || c == 'o' || c == 'm' || c == 'e' || c == 't' || c == 'h' || c == 'i' || c == 'n' || c == 'g') {
// ...
}
if ( c == 's' ||
c == 'o' ||
c == 'm' ||
c == 'e' ||
c == 't' ||
c == 'h' ||
c == 'i' ||
c == 'n' ||
c == 'g') {
// ...
}
That won't work. If any of the strings are null, you'll get a null dereference exception. You need to check them before you use them.
In addition, it's very inefficient. You are concatenating all the strings into a new string, then test if this is non-empty. This results in one or more memory allocations and potentially a lot of data being copied, only to be immediately thrown away and garbage collected a moment later.
A better approach is to write a method that takes variable arguments or a list of strings and checks them one by one using IsNullOrEmpty in a loop. This will be more efficient, safe, but still achieve the desired result of tidy code in your if statement.
If you can get the params in a collection (which if it's function you can with the params keyword) then this might work:
if (myParams.Any(IsNullOrTrimEmpty)
{
// do stuff
}
The example uses this string extension and myParams is a string[].
The original code, though longer, is more clear in its intent, and likely similar performance-wise. I'd leave it alone.

How to check if two string are of the same length?

I want to check if two string are of the same length. I tried the following, but it doesn't work.
string passnew = "1233";
string passcnfrm = "1234";
if((passnew.Length&&passcnfrm.Length)>6 ||(passnew.Length&&passcnfrm.Length)<15)
{
// ...
}
Why does it not work? What do I need to change?
if(passnew.Length == passcnfrm.Length &&
passnew.Length > 6 && passnew.Length < 15)
{
// do stuff
}
You are missing some basic syntax lessons. What you write inside of these brackets are conditions. We have unary operators (operating on one thing), binary operators (two) and one tertiary operator (forget about that one).
You cannot construct something like your "boundary test" with those easily.
A possible way:
(passnew.Length > 6) && (passcnfrm.Length > 6)
But you aren't testing if the length is equal anyway, even if you could use a syntax like that. You seem to want to compare if both are longer than 6 chars and shorter than 15 chars. One at 7 and one at 14 would satisfy both conditions..
if(passnew.Length == passcnfrm.Length &&
(passnew.Length < 15 && passnew.Length > 6))
{
// ...
}
Checks both are same length, and either one is more than 6 and less than 15 characters long.
that would be:
if(passcnfrm.Length.Equals(passnew.Length))
{
//do stuff
}
A probably better way to do it is:
if (( passnew != null && passcnfrm != null )
( passnew == passcnfrm )
&& ( passnew.Length > 6 && passnew.Length < 15 ))
{
// do stuff
}
Hides the length check inside the equality check which you'll probably need, it isn't in your question but the variable names make it pretty clear you're doing a password change function there. I added the null check to make sure the length checks don't throw a NullReferenceException, not needed in the example because you assign both manually, but might save some trouble if you're going to convert this to a method later on.
You can use like this:
if (s.Contains(s1[i]))
or:
boolean equalsIgnoreCase(String anotherString);
or use this method:
public static int occurrence(string [] a, string a2)
{
int occ = 0;
for (int i = 0; i < a.Length;i++ )
{
if(a[i].Equals(a2))
{
occ++;
}
}
return occ;
}

Categories

Resources