Method to validate if string has only hyphens, spaces, Uppercase and digits - c#

Recently I've been trying to create a method to make sure a string has certain types of chars. Yet when I tried using the method, it stops checking if the chars are that way on the 4th character.
For example I tried using 4 lowercase letters and it tells me it's false, but when I try to use invalid characters (lowercase, symbols) on the 5th character, it says it's true:
public bool CarLicensePlateCheck(string m)
{
if (m.Length >= 4 && m.Length <= 12)
{
foreach(char c in m)
{
if (char.IsDigit(c) == true || char.IsUpper(c)==true || char.IsWhiteSpace(c)==true || c.Equals("-"))
return true;
else
break;
}
return false;
}
else
return false;
}

You can try regular expressions and let .Net perform check for you:
using System.Text.RegularExpressions;
...
public static bool CarLicensePlateCheck(string m) =>
m != null && Regex.IsMatch(m, #"^[A-Z0-9\s\-]{4,12}$");
the pattern is
^ - start of the string
[A-Z0-9\s\-]{4,12} - from 4 to 12 characters which are either
in A..Z range - upper case letters
in 0..9 range - digits
\s - white space
\- - dash
$ - end of the string

You need to check if the character is not valid and return false immediately and then return true outside of the foreach (because at that point you've validated all the characters). What you have stops validating after the first character because if the first character is valid it just returns true and if it isn't it breaks from the foreach and returns false.
public bool CarLicensePlateCheck(string m)
{
if (m.Length >= 4 && m.Length <= 12)
{
foreach(char c in m)
{
// If it's not a valid character return false
if (!char.IsDigit(c)
&& !char.IsUpper(c)
&& !char.IsWhiteSpace(c)
&& c != '-')
return false;
}
// all characters have been validated so return true
return true;
}
else
return false;
}

As the code is written now, it only checks the first character. If this character is valid CarLicensePlateCheck returns true. If it is invalid, the loop is broken and CarLicensePlateCheck returns false.
Check instead that the character is invalid and return false immediately, if so. Return true when the whole loop has passed.

Another option to those presented in the other answers is to use LINQ. This results in code that is very short and I think makes the intent very clear.
using System.Linq;
...
public static bool IsValid(char c)
{
return char.IsDigit(c) || char.IsUpper(c) || char.IsWhiteSpace(c) || c == '-';
}
public static bool CarLicensePlateCheck(string m)
{
return m.Length >= 4 && m.Length <= 12 && m.All(c => IsValid(c));
}
This code make use of LINQ's All method, which returns true if a predicate returns true for all elements of a sequence. I also added the static modifier to flag that these methods no not rely on any member variables or properties of the containing class.
Since each function is essentially a single expression this can be rewritten as:
public static bool IsValid(char c) =>
char.IsDigit(c) || char.IsUpper(c) || char.IsWhiteSpace(c) || c == '-';
public static bool CarLicensePlateCheck(string m) =>
m.Length >= 4 && m.Length <= 12 && m.All(IsValid);
It's a matter of taste which of these you prefer.

Related

Why It doesn't work when I declare my variable before?

I worked on an edabit challenge for hours and finally, I resolved this challenge by error.
Here's what didn’t work:
/*****************************/
public static bool IsStrangePair(string str1, string str2)
{
char firstCharInStr1 = str1[0];
char lasttCharInStr1 = str1[str1.Length-1];
char firstCharInStr2 = str2[0];
char lasttCharInStr2= str2[str2.Length-1];
if (str1.Length == 0 && str2.Length == 0)
return true;
if (str1.Length == 0 || str2.Length == 0)
return false;
return firstCharInStr1 == lasttCharInStr2 && lasttCharInStr1 == firstCharInStr2;
}
So I add IsNull at the beginning and it worked :S - why?
public static bool IsStrangePair(string str1, string str2)
{
// A What I add after
if(string.IsNullOrEmpty(str1) || string.IsNullOrEmpty(str2))
{
return str1 == str2;
}
char firstCharInStr1 = str1[0];
char lasttCharInStr1 = str1[str1.Length-1];
char firstCharInStr2 = str2[0];
char lasttCharInStr2= str2[str2.Length-1];
// B-----My first idea
if (str1.Length == 0 && str2.Length == 0)
return true;
if (str1.Length == 0 || str2.Length == 0)
return false;
return firstCharInStr1 == lasttCharInStr2 && lasttCharInStr1 == firstCharInStr2 ;
I didn't understood why it was validate because I was under the impression that my A "IsNullOrEmpty solution" was the repetition of my First Idea so it was insane (for me).
So I understood(i think) that I had to choose between A or B and that the key is to declare my variable AFTER my B or my A ( I have too choose B OR A)
So I'm confused cause I was thinking that we had to declare variables before to start/or use it. Why It doest work when my variables are declared First?
I wish I'm clear
Null can be confusing when first starting up.
Null is not an actual value but rather an empty pointer (if you are familiar with pointers). This means that you have declared a name but you have not actually pointed to any value.
Think of it as you have declare that you want a house of type mansion, but did not declare an address. It is impossible to open maindoor on, but you can check if the address is absent.
You can check for null, you can even in some cases use it to your benefit, however in your case you are trying to take the [0] in a thing that does not exist (is null).
And therefor you have the wonderful option to use string.IsNullOrEmpty(stringToBeTested);
In dot.net 6 you will find green squickly lines everywhere a variables risks being null.

How to check for variable character in string and match it with another string of same length?

I have a rather complex issue that I'am unable to figure out.
I'm getting a set of string every 10 seconds from another process in which the first set has first 5 characters constant, next 3 are variable and can change. And then another set of string in which first 3 are variable and next 3 are constant.
I want to compare these values to a fixed string to check if the first 5 char matches in 1st set of string (ABCDE*** == ABCDEFGH) and ignore the last 3 variable characters while making sure the length is the same. Eg : if (ABCDE*** == ABCDEDEF) then condition is true, but if (ABCDE*** == ABCDDEFG) then the condition is false because the first 5 char is not same, also if (ABCDE*** == ABCDEFV) the condition should be false as one char is missing.
I'm using the * in fixed string to try to make the length same while comparing.
Does this solve your requirements?
private static bool MatchesPattern(string input)
{
const string fixedString = "ABCDExyz";
return fixedString.Length == input.Length && fixedString.Substring(0, 5).Equals(input.Substring(0, 5));
}
In last versions of C# you can also use ranges:
private static bool MatchesPattern(string input)
{
const string fixedString = "ABCDExyz";
return fixedString.Length == input.Length && fixedString[..5].Equals(input[..5]);
}
See this fiddle.
BTW: You could probably achieve the same using regex.
It's always a good idea to make an abstraction. Here I've made a simple function that takes the pattern and the value and makes a check:
bool PatternMatches(string pattern, string value)
{
// The null string doesn't match any pattern
if (value == null)
{
return false;
}
// If the value has a different length than the pattern, it doesn't match.
if (pattern.Length != value.Length)
{
return false;
}
// If both strings are zero-length, it's considered a match
bool result = true;
// Check every character against the pattern
for (int i = 0; i< pattern.Length; i++)
{
// Logical and the result, * matches everything
result&= (pattern[i]== '*') ? true: value[i] == pattern[i];
}
return result;
}
You can then call it like this:
bool b1 = PatternMatches("ABCDE***", "ABCDEFGH");
bool b2 = PatternMatches("ABC***", "ABCDEF");
You could use regular expressions, but this is fairly readable, RegExes aren't always.
Here is a link to a dotnetfiddle: https://dotnetfiddle.net/4x1U1E
If the string you match against is known at compile time, your best bet is probably using regular expressions. In the first case, match against ^ABCDE...$. In the second case, match against ^...DEF$.
Another way, probably better if the match string is unknown, uses Length, StartsWith and EndsWith:
String prefix = "ABCDE";
if (str.Length == 8 && str.StartsWith(prefix)) {
// do something
}
Then similarly for the second case, but using EndsWith instead of StartsWith.
check this
public bool Comparing(string str1, string str2)
=> str2.StartWith(str1.replace("*","")) && str1.length == str2.Length;

C# Should I initialize a bool as false or should I make it false in an else statement? Best practice?

I have the two following pieces of code, in one I initialize the isSpclChar bool as false, in the other one I catch the false state later in an else statement:
static bool CheckSpclChar(char _letter)
{
bool isSpclChar = false;
if(_letter == '!' || _letter == '#')
{
isSpclChar = true;
}
return isSpclChar;
}
And:
static bool CheckSpclChar(char _letter)
{
bool isSpclChar;
if(_letter == '!' || _letter == '#')
{
isSpclChar = true;
}
else
{
isSpclChar = false;
}
return isSpclChar;
}
Which of them is best practice or less prone to errors in this type of case?
Does it not matter at all?
No need for an else at all:
bool isSpecialChar = _letter == '!' || _letter == '#';
In fact, your whole method can be simplified to:
static bool CheckSpecialChar(char letter) => letter == '!' || letter == '#';
I've expanded "Spcl" to "Special" for better readability, and removed the leading prefix from the parameter name to follow .NET conventions. You might also want to consider using Is instead of Check.
Finally, you might want to avoid using the word "special" in the method name too. I tend to wince when I hear the phrase "special character" because without more specific context, it's meaningless. What do ! and # mean in this context? Is there a more useful description you could give, such as IsEscapePrefix or something similar?
We should use variables when we need to use that values, otherwise you just need to write your method as follows. Let me know, if that makes sense?
static bool CheckSpclChar(char _letter)
{
if(_letter == '!' || _letter == '#')
{
return true;
}
return false;
}

Palindrom recursion: Simplify conditional ternary expression

I needed to implement a recursive method that checks whether an input is a palindrome or not. I was able to do this in one line and it works, but I'm not sure about how readable this is. I also keep getting a message "Simplify conditional ternary expression" but I'm not sure how
this is my code:
private static bool checkIfPalindrome(string i_InputToCheck, int i_StartIndex, int i_EndIndex)
{
return (i_StartIndex >= i_EndIndex) ? true : checkIfPalindrome(i_InputToCheck, i_StartIndex + 1, i_EndIndex - 1) && (i_InputToCheck[i_StartIndex] == i_InputToCheck[i_EndIndex]);
}
how readable this is
First off, naming convention: Get rid of unnecessary/uninformative parts of identifiers. For example, parameters do not need to start with i_ (presumably to denote “input”?). There’s no information conveyed here, and it adds noise. This has a huge impact on readability.
The logic itself can also be decluttered. The warning you’re getting gives you a hint that the condition can be simplified — this is always the case when your conditionals contain boolean literals.
More than anything, however, readability would benefit from breaking the expression up over multiple lines.
I would also swap the two secondary conditions, so that you first test the current characters, and then recurse further (only if the two currently tested characters are equal!):
private static bool IsPalindrome(string input, int start, int end) {
return (start >= end) ||
input[start] == input[end] &&
IsPalindrome(input, start + 1, end - 1);
}
This code relies on the correct precedence of && over ||. Some peope prefer making this operator precedence explicit by using more parentheses:
private static bool IsPalindrome(string input, int start, int end) {
return (start >= end) ||
(
input[start] == input[end] &&
IsPalindrome(input, start + 1, end - 1)
);
}
return i_StartIndex >= i_EndIndex || checkIfPalindrome(i_InputToCheck, i_StartIndex + 1, i_EndIndex - 1) && i_InputToCheck[i_StartIndex] == i_InputToCheck[i_EndIndex];
The simplification being prompted is because you're testing a boolean expression and then unnecessarily checking and returning it...
if (expression == true) is equivalent to if (expression) and
return expression ? true : false to return expression.
It is certainly not easy on the eye but I assume this is for a school exercise?

CollectionView multiple filter

I want to do something like Google does in its search: if the user write some special char, like - or * the results are filtered.
What I have now: a filter that filters objects Name property with Contains method, and two special characters:
for leaving only the names that don't contain the typed text -
for searching a different property of my object (in my case it is Units) *
Ok, what I need is to combine above logic and be able to first filter with "-" or "*" and then be able to type and continue filtering the remaining results.
It's all about the logic I think, but it's getting complicated and I might need a little help.
item.View.Filter = delegate(object o)
{
//Lógica de filtrado
if ((item.FilterText.Length > 0) && ((item.FilterText[0] == '*') || (item.FilterText[0] == '-')))
{
//If the first char is *
if ((item.FilterText[0] == '*')
&& (((MyObject)o).Units[0].ToString().ToUpper(CultureInfo.InvariantCulture)
.Contains(item.FilterText.ToUpper(CultureInfo.InvariantCulture).Substring(1))
|| ((MyObject)o).Units[1].ToString().ToUpper(CultureInfo.InvariantCulture)
.Contains(item.FilterText.ToUpper(CultureInfo.InvariantCulture).Substring(1))))
{
return true;
}
//If the first char is -
if ((item.FilterText[0] == '-')
&& (!((MyObject)o).Name.ToUpper(CultureInfo.InvariantCulture)
.Contains(item.FilterText.ToUpper(CultureInfo.InvariantCulture).Substring(1))
|| !((MyObject)o).Name.ToUpper(CultureInfo.InvariantCulture)
.Contains(item.FilterText.ToUpper(CultureInfo.InvariantCulture).Substring(1))))
{
return true;
}
}
else
{
if (((MyObject)o).Name.ToUpper(CultureInfo.InvariantCulture)
.Contains(item.FilterText.ToUpper(CultureInfo.InvariantCulture)))
{
return true;
}
}
return false;
};

Categories