More Efficient OR Statement - c#

I currently have C# code checking for user input as such:
if (e.KeyCode == Keys.Enter && InputTextbox.Text.Contains("good morning")
||
e.KeyCode == Keys.Enter && InputTextbox.Text.Contains("morning"))
Is there another way to use the || "or" statement so that it can all be in the one line? Something like:
if (e.KeyCode == Keys.Enter && InputTextbox.Text.Contains("good morning" || "morning")

You can create an array with the values you want to check and then check if the array contains the TextBox value
string[] a = {"good morning" , "morning");
if (e.KeyCode == Keys.Enter && a.Contains(InputTextbox.Text))
{
}

var allowedText = new List<string> { "good morning", "morning" };
if (e.KeyCode == Keys.Enter && allowedText.Contains(InputTextbox.Text))
{
// do something
}

Hm, for instance: if your InputTextBox is: "Hello good morning" I don't think the above answers will work, if this is what you seek (having a posibly larger string checked against the given smaller strings), you have to check it the other way around:
if (e.KeyCode == Keys.Enter && (InputTextbox.Text.Contains("good morning") || InputTextbox.Text.Contains("morning"))
Just thought I'd point it out, if not the case ignore this answer.

This is sufficient:
if (e.KeyCode == Keys.Enter && InputTextbox.Text.Contains("morning"))
{
}
It is because if InputTextbox.Text.Contains("good morning") is true, InputTextbox.Text.Contains("morning") must be true as well.

Related

Accepting empty textboxes in c# for a datagridview

I have a list of existing products presented in a datagridview. User can add new product using this window
Some of the fields can be accepted as empty. The text field must have char only and the int fields must have positive int only. ID, price, playtime and status must be positive ints. The rest must be chars, when they aren't empy that is. The code i have works but only when every field that could be empty is empty. It doesn't work if some are and others aren't.
It would also be nice if you could solve the issue of accepting empty int fields.myint.ToString().Length; is not getting the job done seems like. Maybe the answer is easy but I'm sorta new to C# and .Net.
Here is the code i wrote
if (!plist.type.Any() || !plist.author.Any() || !plist.genre.Any() || !plist.format.Any() || !plist.language.Any() || !plist.platform.Any())
{
if (plist.id != Math.Abs(plist.id) || plist.price != Math.Abs(plist.price)
|| plist.playtime != Math.Abs(plist.price) || plist.status != Math.Abs(plist.price))
{
DialogResult = DialogResult.No;
}
else if (plist.type.Any(char.IsDigit) || plist.name.Any(char.IsDigit)
|| plist.author.Any(char.IsDigit) || plist.genre.Any(char.IsDigit)
|| plist.format.Any(char.IsDigit) || plist.language.Any(char.IsDigit) || plist.platform.Any(char.IsDigit))
{
DialogResult = DialogResult.No;
}
else
{
DialogResult = DialogResult.OK;
}
}
else
{
DialogResult = DialogResult.OK;
}
Let me know if there is anything left to clear up.
I appreaciate any suggestions you got for me!
Assuming that type, author, genre, format, language and platform are mandatory fields, you should be setting DialogResult to DialogResult.No instead of OK in your bottom most else statement. Otherwise, you will be skipping your logic and returning the wrong result.
if (!plist.type.Any() || !plist.author.Any() || !plist.genre.Any() || !plist.format.Any() || !plist.language.Any() || !plist.platform.Any())
{
if (plist.id != Math.Abs(plist.id) || plist.price != Math.Abs(plist.price)
|| plist.playtime != Math.Abs(plist.price) || plist.status != Math.Abs(plist.price))
{
DialogResult = DialogResult.No;
}
else if (plist.type.Any(char.IsDigit) || plist.name.Any(char.IsDigit)
|| plist.author.Any(char.IsDigit) || plist.genre.Any(char.IsDigit)
|| plist.format.Any(char.IsDigit) || plist.language.Any(char.IsDigit) || plist.platform.Any(char.IsDigit))
{
DialogResult = DialogResult.No;
}
else
{
DialogResult = DialogResult.OK;
}
}
else
{
DialogResult = DialogResult.No;
}
As for the empty integer length issue, make sure that you are not trying to turn a null value to a string. Consider using a numericUpDown instead of a textbox as the numericUpDown is designed to work with numbers. You can even set limits to you numbericUpDown, like a lower number limit to prevent negative numbers.
https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.numericupdown?view=windowsdesktop-7.0

How to translate conditions (without brackets) correctly?

I have condition, where are no ( ) brackets inside coded by programmer... How can I bracket such ugly coded correctly?
if( c_1 && c_2 || c_3 || c_4 && c_5 || c_6 && c_7 || c_8 || c_9 && c_10)
&& has higher precedence1 in C# than ||. That means your expression is effectively:
if ((c_1 && c_2) || c_3 || (c_4 && c_5) || (c_6 && c_7) || c_8 || (c_9 && c_10))
For further readability, I'd probably extract conditions into local variables with meaningful names. For example:
bool recentlyActive = (c_1 && c_2) || c_3;
bool passwordDisabled = (c_4 && c_5) || (c_6 && c_7);
bool userBanned = c_8 || (c_9 && c_10);
if (recentlyActive || passwordDisabled || userBanned)
{
...
}
1 Precedence in C# is documented in the specification, but it really comes directly out of the grammar. I'm glad of that documentation though, because I wouldn't want to have to read the grammar every time I wanted to understand how operators bind...

C# Looking for similar needle in haystack (for OCR)

I've been working on an OCR program that accepts a photo with text in it (in this specific case, a driver's license) as well as a first name and a last name as arguments.
Once the software reads the id photo, I search for the first and last name in the recognized text. Unfortunately, as the image quality can be pretty low, it will sometimes not get the name quite right.
Is there a way I could look for a SIMILAR needle in a haystack? That is, look for any occurrences that are similar to the first/last name? For example:
Needle: campbell
Haystack:
operaioxsllcence
gcltdriver
exries13NOV2020
carnpbeiljtttj
...
The string that would be close enough is "carnpbeil".
This is what I'm using now, and it only helps in very specific situations:
private bool SourceContains(string haystack, string needle)
{
bool ret = false;
if (haystack.Contains(needle) ||
haystack.Replace("l", "i").Contains(needle) ||
haystack.Replace("i", "l").Contains(needle) ||
haystack.Replace("0", "o").Contains(needle) ||
haystack.Replace("o", "0").Contains(needle) ||
haystack.Replace("j", "d").Contains(needle) ||
haystack.Replace("d", "j").Contains(needle) ||
haystack.Replace("i", "j").Contains(needle) ||
haystack.Replace("j", "i").Contains(needle) ||
haystack.Replace("e", "f").Contains(needle) ||
haystack.Replace("f", "e").Contains(needle) ||
haystack.Replace("r", "p").Contains(needle) ||
haystack.Replace("p", "r").Contains(needle) ||
haystack.Replace("s", "r").Contains(needle) ||
haystack.Replace("r", "s").Contains(needle) ||
haystack.Replace("r", "n").Contains(needle) ||
haystack.Replace("n", "r").Contains(needle) ||
haystack.Replace("k", "n").Contains(needle) ||
haystack.Replace("n", "k").Contains(needle) ||
haystack.Replace("h", "n").Contains(needle) ||
haystack.Replace("n", "h").Contains(needle) ||
haystack.Replace("k", "ll").Contains(needle) ||
haystack.Replace("ll", "k").Contains(needle) ||
haystack.Replace("ci", "d").Contains(needle) ||
haystack.Replace("d", "ci").Contains(needle) ||
haystack.Replace("cl", "d").Contains(needle) ||
haystack.Replace("d", "cl").Contains(needle) ||
haystack.Replace("m", "in").Contains(needle) ||
haystack.Replace("in", "m").Contains(needle) ||
haystack.Replace("rn", "m").Contains(needle) ||
haystack.Replace("m", "rn").Contains(needle)
)
{
ret = true;
}
return ret;
}
For each word in haystack calculate the levenshtein distance to needle. The word with the shortest distance is most likely to be your needle. Have a look at this question for implementations.

How to prevent a textbox from entering a character more than once

I don't want the textbox to let the user to enter letters and the following characters '-' ,'.' more than once, but allow them to press the 'Enter' Key. I'm using the below code:
private void textBox3_KeyPress(object sender, KeyPressEventArgs e)
{
if (char.IsNumber(e.KeyChar) || e.KeyChar == 8 || e.KeyChar == '.' || e.KeyChar == '-')
{
return;
}
else
{
e.Handled = e.KeyChar != (char)Keys.Back;
MessageBox.Show("X Origin Can Only Accepts Numbers, a Point '.' and a minus '-'", "ATTENTION", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
I agree with the suggestion from commenter Sinatr that it would be better to display the validation result in some other way. That said, taking your question literally – i.e. to prevent the user from entering even permitted characters more than once – one implementation might look something like this:
private readonly HashSet<char> _enteredChars = new HashSet<char>();
private void textBox3_KeyPress(object sender, KeyPressEventArgs e)
{
if ((char.IsNumber(e.KeyChar) || e.KeyChar == 8 || e.KeyChar == '.' || e.KeyChar == '-') &&
_enteredChars.Add(e.KeyChar))
{
return;
}
else
{
e.Handled = e.KeyChar != (char)Keys.Back;
MessageBox.Show("X Origin Can Only Accepts Numbers, a Point '.' and a minus '-'", "ATTENTION", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
This uses a HashSet<char> to store each character already entered. If a key is pressed and the character is already in the set (i.e. Add() returns false), the code will jump to the same error handling used for invalid characters.
You can of course modify the above example to handle the "already entered" scenario differently from the "invalid character", i.e. to present a different error message, or even to just ignore those key presses.
Also note that the set is only ever added to here. You would want to track the removal of characters from the field, removing them from the HashSet<char> at the same time. You could simplify this aspect by simply examining the text field directly for each key press instead of using the HashSet<char>. That is:
TextBox textBox = (TextBox)sender;
if ((char.IsNumber(e.KeyChar) || e.KeyChar == 8 || e.KeyChar == '.' || e.KeyChar == '-') &&
!textBox.Text.Contains(e.KeyChar))
For very long text entries, this could be a bit slower than the HashSet<char> based approach. But otherwise I doubt you'd notice a difference, and for very short text entries this could even be faster.
The advantage of using the textBox.Text property directly is that it's simpler; you don't have to worry about keeping anything in sync with the data entered so far, as you're always just checking that data directly.

Is there a "grouped" way to know if the PreviewKeyDown key is Delete, Home, End, Pg Up, Etc

I have a PreviewKeyDown event that I use to filter my input (I need to filter out spaces among other things, so using PreviewKeyPress is out).
It is all working fine, except it eats my Delete, Backspace, Home, Arrow, Page Up etc keypresses.
I can just try to think of all the keys that I think should be allowed and tell my event to ignore them:
if ((e.Key == Key.Up) || (e.Key == Key.Down) || (e.Key == Key.Left)
|| (e.Key == Key.Right) || (e.Key == Key.Delete) || (e.Key == Key.Home)
|| (e.Key == Key.End) || (e.Key == Key.PageUp) || (e.Key == Key.Insert)
|| (e.Key == Key.F1))
But I am sure I will miss some.
Is there a better way that just making a huge "Or" statement and hoping I got them all?
I'd do the filtering in KeyPress. At that point you'll deal with characters, and not with keys. So you don't need to care about most of them (AFAIR there are a handful of exceptions, such as return or backspace).
Use e.Handled to supress characters.
I am using this: How do you get the character appropriate for the given KeyDown event? to convert my key value to a char.
I realized that if the key is not a valid char, then it is being set to ASCII 32 (SPACE).
So I am just going to filter off of that....
// If this was not a true char then it will convert to the ASCII Space (#32).
// If this is not really a char, then we are done.
if ((newChar == (char)32) && (e.Key != Key.Space))
return;

Categories

Resources