string to double validation c# please answer - c#

ok so I am building a program in WPF format.
as you know wpf's inputs are usually string, to turn those into double first I need to validate if those string fit and then to proceed and convert them.
the problem is in the validation, I have done the part in the validation that is checking if the string.IsNullOrEmpty but the thing I could not do is validate if the answer is completely not convertable... let me show an example because some strings that are not completely numeric are still should be accepted for example:
"sadasdaasd" - not accepted (obviously)
"8945a4554" - not accepted (there is an 'a' in the middle)
"3519" - accepted
"12.55" - accepted
"-3/4" - accepted and the value should be converted to double as (-3) divided by (4). so '/' is accepted and it splits the string by 2 and then converts it to double as first part/ second part.
I have been trying to do this validation all day and still have not succeeded, I have tried searching the web for some input validation, some said that I need to use double.TryParse(string, out double) but this function does not work with the '/' split that i wanted. so please help me!!!

I would start by parsing your string via regex (q: is "-3*4" acceptable as -3 times 4?). Basically you're looking for a match on a regex which is kind of like this (this works on -3/4, you'd want to test it further and modify if multiplication is allowed): -?\d+[/]\d+
If you find that match, parse out your string with string.Split('/') which will give you an array of strings. TryParse each of those and do the math.
If there is not a match, use TryParse (as recommended previously). That will either succeed (3519, 12.55 in your examples) or fail (sadasdaasd, 8945a4554 in your examples).
Note: you could also use string.Contains('/'), but then you have to check to see if it holds more than one slash (unless such a thing is allowed- in which case you'll need to revisit that regex).

Related

String interpolation C#: Documentation of colon and semicolon functionality

I found this codegolf answer for the FizzBuzz test, and after examining it a bit I realized I had no idea how it actually worked, so I started investigating:
for(int i=1; i<101;i++)
System.Console.Write($"{(i%3*i%5<1?0:i):#}{i%3:;;Fizz}{i%5:;;Buzz}\n");
I put it into dotnetfiddle and established the 1st part works as follows:
{(BOOL?0:i):#}
When BOOL is true, then the conditional expression returns 0 otherwise the number.
However the number isn't returned unless it's <> 0. I'm guessing this is the job the of :# characters. I can't find any documentation on the :# characters workings. Can anyone explain the colon/hash or point me in the right direction?
Second part:
{VALUE:;;Fizz}
When VALUE = 0 then nothing is printed. I assume this is determined by the first ; character [end statement]. The second ; character determines 'if VALUE <> 0 then print what's after me.'
Again, does anyone have documentation on the use of a semicolon in string interpolation, as I can't find anything useful.
This is all covered in the String Interpolation documentation, especially the section on the Structure of an Interpolated String, which includes this:
{<interpolatedExpression>[,<alignment>][:<formatString>]}
along with a more detailed description for each of those three sections.
The format string portion of that structure is defined on separate pages, where you can use standard and custom formats for numeric types as well as standard and custom formats for date and time types. There are also options for Enum values, and you can even create your own custom format provider.
It's worth taking a look at the custom format provider documentation just because it will also lead you to the FormattableString type. This isn't well-covered by the documentation, but my understanding is this type may in theory allow you to avoid re-parsing the interpolated string for each iteration when used in a loop, thus potentially improving performance (though in practice, there's no difference at this time). I've written about this before, and my conclusion is MS needs to build this into the framework in a better way.
Thanks to all the commenters! Fast response.
The # is defined here (Custom specifier)
https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-numeric-format-strings#the--custom-specifier
The "#" custom format specifier serves as a digit-placeholder symbol.
If the value that is being formatted has a digit in the position where
the "#" symbol appears in the format string, that digit is copied to
the result string. Otherwise, nothing is stored in that position in
the result string. Note that this specifier never displays a zero that
is not a significant digit, even if zero is the only digit in the
string. It will display zero only if it is a significant digit in the
number that is being displayed.
The ; is defined here (Section Seperator):
https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-numeric-format-strings#the--section-separator
The semicolon (;) is a conditional format specifier that applies
different formatting to a number depending on whether its value is
positive, negative, or zero. To produce this behavior, a custom format
string can contain up to three sections separated by semicolons...

c# string format validate

Update: The acceptable format is ADD|| .
I need to check if the request that the server gets, is in this format, and the numbers are between <>.
After that I have to read the numbers and add them and write the result back. So, if the format not fits to for example ADD|<5>|<8>
I have to refuse it and make a specific error message(it is not a number, it is wrong format, etc.). I checked the ADD| part, I took them in an array, and I can check, if the numbers are not numbers. But I cannot check if the numbers are in <> or not, because the numbers can contain multiple digits and ADD|<7>|<13> is not the same number of items likeADD|<2358>|<78961156>. How can I check that the numbers are in between <>?
please help me with the following: I need to make a server-client console application, and I would like to validate requests from the clients. The acceptable format is XXX|<number>|<number>.
I can split the message like here:
string[] messageProcess = message.Split('|');
and I can check if it is a number or not:
if (!(double.TryParse(messageProcess[1], out double number1)) || !(double.TryParse(messageProcess[2], out double number2)))
but how can I check the <number> part?
Thank you for your advice.
You can use Regex for that.
If I understood you correctly, follwing inputs should pass validation:
xxx|1232|32133
xxx|5345|23423
XXX|1323|45645
and following shouldn't:
YYY|1231|34423
XXX|ds12|sda43
If my assumptions are correct, this Regex should do the trick:
XXX\|\d+\|\d+
What it does?
first it looks for three X's... (if it doesn't matter if it's uppercase or lowercase X substitute XXX with (?:XXX|xxx) or use "case insensitive regex flag" - demo)
separated by pipe (|)...
then looks for more than one digit...
separated by pipe (|)...
finally ending with another set of one or more digits
You can see the demo here: Regex101 Demo
And since you are using C#, the Regex.IsMatch() would probably fit you best. You can read about it here, if you are unfamiliar with regular expressions and how to use them in C#.

Decimal.TryParse Fails to parse integer value

What am I missing:
decVal = Decimal.Parse(myAr[0]);
Or
Decimal.TryParse(myAr[0], out decVal);
Fails !
Input string was not in correct foramt.
myAr[0] is "678016".
Tried to add NumberStyle.Any and CultureInfo.InvarialtCulture but got the same results.
More info on the string:
it is concatenated with some letters in hebrew and a "\u200e" space between them. and then I use split(' ') to get the numbers back.
This is probably the source of this error, but when I check the myAr[0] in the watch it is pure string....
Guys I've found the answer, I'll rewrite the question for future generation.
The Original string was a concatenation of letters and numbers separated with a special sequence to preserve the order in a rtl situation: "\u200E".
The number where extracted later using string.split(' ') which seems to work OK (in the watch) be it caused the problem.
once I used string.split("\u200e").ToCharArray() I got the same results, but now the decimal.Parse is working.
It looks like the special char was still inside the string, invisible to the watch.
This is weird, on my machine (.NET 4) even this works:
Decimal.TryParse("asdf123&*", out someDecimal);
By works I mean that TryParse returns false, no exception is thrown.
Parse method may throw an exception - maybe you have some whitespace or string literally contains " (quotes)?

custom string format puzzler

We have a requirement to display bank routing/account data that is masked with asterisks, except for the last 4 numbers. It seemed simple enough until I found this in unit testing:
string.Format("{0:****1234}",61101234)
is properly displayed as: "****1234"
but
string.Format("{0:****0052}",16000052)
is incorrectly displayed (due to the zeros??): "****1600005252""
If you use the following in C# it works correctly, but I am unable to use this because DevExpress automatically wraps it with "{0: ... }" when you set the displayformat without the curly brackets:
string.Format("****0052",16000052)
Can anyone think of a way to get this format to work properly inside curly brackets (with the full 8 digit number passed in)?
UPDATE: The string.format above is only a way of testing the problem I am trying to solve. It is not the finished code. I have to pass to DevExpress a string format inside braces in order for the routing number to be formatted correctly.
It's a shame that you haven't included the code which is building the format string. It's very odd to have the format string depend on the data in the way that it looks like you have.
I would not try to do this in a format string; instead, I'd write a method to convert the credit card number into an "obscured" string form, quite possibly just using Substring and string concatenation. For example:
public static string ObscureFirstFourCharacters(string input)
{
// TODO: Argument validation
return "****" + input.Substring(4);
}
(It's not clear what the data type of your credit card number is. If it's a numeric type and you need to convert it to a string first, you need to be careful to end up with a fixed-size string, left-padded with zeroes.)
I think you are looking for something like this:
string.Format("{0:****0000}", 16000052);
But I have not seen that with the * inline like that. Without knowing better I probably would have done:
string.Format("{0}{1}", "****", str.Substring(str.Length-4, 4);
Or even dropping the format call if I knew the length.
These approaches are worthwhile to look through: Mask out part first 12 characters of string with *?
As you are alluding to in the comments, this should also work:
string.Format("{0:****####}", 16000052);
The difference is using the 0's will display a zero if no digit is present, # will not. Should be moot in your situation.
If for some reason you want to print the literal zeros, use this:
string.Format("{0:****\0\052}", 16000052);
But note that this is not doing anything with your input at all.

How to safely and correctly convert a number from user input to double?

This is, basically, a CultureInfo problem. Formally, in my country, the decimal separator is a comma (,) and a thousands separator is a dot (.). In practice, however, this is only used by accountants and diligent people. Normally people never use a thousands separator, and they use both a comma and a dot interchangeably as a decimal separator. I've seen this being the problem even in some Excel spreadsheets that I received from other people, with Excel not having recognized a dot as a decimal separator, leaving the field formatted as a string, rather than a number.
My "solution" thus far has been to simply replace all commas in user input with dots and then parsing the double with InvariantCulture, like so:
string userInput;
...
userInput = userInput.Replace(',', '.');
double result;
double.TryParse(userInput, NumberStyles.Float, CultureInfo.InvariantCulture, out result);
This will obviously fail when someone actually enters the thousands separator and this seems to me more like a hack than a real solution. So, other than making my own parser for doubles, are there any cleaner ways to handle this problem?
If you are using ASP.Net you can use the AjaxControlToolkit FilteredTextBox you can also accomplish the task using regular expressions and pattern matching. It is nearly always better to try and get a standard input than attempting to deal with every possible human input variable.
Some other links:
MaskedTextBox
WPF Tools FilteredTextBox
If there are rules that can conclusively determine what they meant, then you can code the logic. With this problem, though, it is impossible to know the intent in every case:
1,001 === 1.001 or 1001
Also, even though any "better" logic might assume that numbers like "1,01" are unambiguous, such an entry might be a typo of "1,001." How likely this is depends on what kind of data you're gathering.
If people rarely use a thousands separator, then your existing logic seems good. If you want to be 100% certain of intent, though, the only way to be sure is to ask them what they meant in such cases. E.g. if someone enters 1,001 or 1.001 then fail validation, but recode it as "1,001.0" (or .00 if dealing with currency) to disambiguate it, forcing them to resumbit it.
In practice, you probably would cause more harm than good with this kind of abundance of caution since people don't really use the thousands separator. I'd stick with what you got.

Categories