C# FormatException Unhandled when converting Hex to decimal - c#

So I am still learning C#, and i have a bit of a problem. I am making a very simple windows forms application, with two text boxes, input and Output, For conversions from hex to dec. Here is my code:
string input = textBox1.Text;
int Output = Convert.ToInt32(input, 16);
textBox2.Text = Output.ToString();
//Textbox1 is Input
//Textbox2 is Output

There are potentially two exceptions you're going to run into here. First, is a FormatException like you described. This can occur if the input string isn't formatted correctly; say it contains a non hex character, a space, or something else. The other exception you will encounter is an overflow exception, when the hex from the first text box becomes a number too large for a 32 bit integer.
To handle the exceptions, you're going to need a try catch block. Check out https://msdn.microsoft.com/en-us/library/0yd65esw.aspx for more info on the try catch.
A better way of writing this with some error checking might look like something below:
string input = textBox1.Text;
try
{
int Output = Convert.ToInt32(input, 16);
textBox2.Text = Output.ToString();
}
catch (FormatException)
{
MessageBox.Show("Input string is not in the correct format.");
}
catch (OverflowException)
{
MessageBox.Show("Input is too large for conversion.");
}
//Textbox1 is Input
//Textbox2 is Output
As Shar1er80 and Landepbs have pointed out, the code you provided won't error if your input is correct. It's your job as the programmer to validate that the input will not error. You can do an error check with a regular expression as Shar1er80 has suggested, but there are other ways as well. You will not only need to check that the input contains valid characters for conversion to hex, you also should check the length. Each Hex character can be one of 16 possible values (0-F). Putting two of them together yields 256 possible values, or exactly one byte. A 32 bit integer is 4 bytes, meaning your maximum length of valid input is 8 characters. Any more, and the integer will overflow.
You should also decide if you want to use a signed integer as you have or an unsigned integer. In signed integers, one bit is used for the sign, so the largest positive integer you can output is half what it would be for an unsigned integer. You can read more about integers and sign at https://msdn.microsoft.com/en-us/library/5kzh1b5w.aspx.
Good luck learning C# and stick with it!

What is the problem? This code looks good with one exception, HEX is limited to 0 - 9 and A - F. I would suggest adding input validation for this.
EDITED:
Check this SO answer for validating hex input
Check a string to see if all characters are hexadecimal values

Related

numeric format strings #,#0.00 vs #,0.00

I tried to figure out the basics of these numeric string formatters. So I think I understand the basics but there is one thing I'm not sure about
So, for example
#,##0.00
It turns out that it produces identical results as
#,#0.00
or
#,0.00
#,#########0.00
So my question is, why are people using the #,## so often (I see it a lot when googling)
Maybe I missed something.
You can try it out yourself here and put the following inside that main function
double value = 1234.67890;
Console.WriteLine(value.ToString("#,0.00"));
Console.WriteLine(value.ToString("#,#0.00"));
Console.WriteLine(value.ToString("#,##0.00"));
Console.WriteLine(value.ToString("#,########0.00"));
Probably because Microsoft uses the same format specifier in their documentation, including the page you linked. It's not too hard to figure out why; #,##0.00 more clearly states the programmer's intent: three-digit groups separated by commas.
What happens?
The following function is called:
public string ToString(string? format)
{
return Number.FormatDouble(m_value, format, NumberFormatInfo.CurrentInfo);
}
It is important to realize that the format is used to format the string, but your formats happen to give the same result.
Examples:
value.ToString("#,#") // 1,235
value.ToString("0,0") // 1,235
value.ToString("#") // 1235
value.ToString("0") // 1235
value.ToString("#.#")) // 1234.7
value.ToString("#.##") // 1234.68
value.ToString("#.###") // 1234.679
value.ToString("#.#####") // 1234.6789
value.ToString("#.######") // = value.ToString("#.#######") = 1234.6789
We see that
it doesn't matter whether you put #, 0, or any other digit for that matter
One occurrence means: any arbitrary large number
double value = 123467890;
Console.WriteLine(value.ToString("#")); // Prints the full number
, and . however, are treated different for double
After a dot or comma, it will only show the amount of character that are provided (or less: as for #.######).
At this point it's clear that it has to do with the programmer's intent. If you want to display the number as 1,234.68 or 1234.67890, you would format it as
"#,###.##" or "#,#.##" // 1,234.68
"####.#####" or "#.#####" // 1234.67890

PadLeft and PadRight using variables given in by user

I have a small problem using PadLeft and PadRight.
So I have in my code that the user can input the character they want to use for padding and how many characters they wanna put in. Like this:
String StartString;
int AmountOfCharacters;
Char PadCharacter;
StartString = TextBoxString.Text(Lawnmower)
AmountOfCharacters = Convert.ToInt32(TextBoxAmountofCharacters.Text) (Lets Say 5)
PadCharacter = Convert.ToChar(TextBoxPadCharacter.Text)(Lets use *)
So then later i have put.
Padding = String.PadLeft(AmountOfCharacters,PadCharacter)
Now the problem I have when I run the code as I have it above it doesn't do anything.
It just gives me as text lawnmower without any **** attatched.
Do I have to change something in my code to make it work or am I using the wrong variables for this?
Because when I use the PadCharacter as a String to I get a error message
Cannot implicitly convert String to char.
You misunderstand how PadLeft() works. The length you specify as a parameter (in your case AmountOfCharacters) does not specify how many characters you want added but how many characters the string should have at the end (at least).
So when you specify the string "Lawnmower" and AmountOfCharacters = 5, nothing will happen because the word Lawnmower is already more than 5 characters long.
If StartString charecter count is less then AmountOfCharacters you can see stars infront of StartString. The number of stars will be
[AmountOfCharacters] - [StartString Character Count]
String is a sequence of characters, but not itself a character - that's why Convert.ToChar fails with an exception. Try TextBoxPadCharacter[0] to get the first character of user input. You will also need to verify that the input is non-empty.

Printing Hexadecimals as Hexadecimals in C#?

I need to send an array of bytes to a hardware (SDZ16 matrix) using a Serial Port. The trick is in the fact that that hardware expects strings of hexadecimal and ASCII characters.
When assigning values to the array of bytes, even if I set the bytes to an explicit hexadecimal value
(bytes[0] = 0xF2, for instance), it will print the equivalent decimal value (242 instead of F2).
I am suspicious that the problem is in the Console.WriteLine(); which when printing each byte sets them by default as integers(?) How does C# keep track that there is an Hexadecimal value inside an int?
If I assign bytes[0] = 0xF2; will the hardware understand it in hexadecimal even if Console.WriteLine(); shows differently will testing?
If you want to get a string representation in hex format you can do so by using a corresponding numeric format string:
byte value = 0xF2;
string hexString = string.Format("{0:X2}", value);
Note that Console.WriteLine has an overload that takes a format string and a parameter list:
Console.WriteLine("{0:X2}", value);
Update: I just had a glimpse at the documentation here, and it seems that you need to send commands by providing the corresponding ASCII representation in the form of a string. You can get the ASCII representation using:
byte value = 0x01;
string textValue = value.ToString().PadLeft(2, '0');
byte[] ascii = Encoding.ASCII.GetBytes(textValue)
My tip would be to carefully check the documentation of your equipment to find out which exact format is expected.
it will print the equivalent decimal value (242 instead of F2).
Yes because 0xF2 is still 242. It is just an hexadecimal notation. Most comman prefix is 0x in this notation. Even if you use debugger, you can see it's decimal notation.
I am suspicious that the problem is in the Console.WriteLine(); which
when printing each byte sets them by default as integers(?)
No, Console.WriteLine() method nothing do here.
How does C# keep track that there is an Hexadecimal value inside an
int?
There is no such a thing as Hexadecimal value inside an int. It is just a notation.
If you wanna hexadecimal notation of a number, you can use The hexadecimal "X" format specifier like;
byte b = 0xF2;
Console.WriteLine(b.ToString("X")); //F2
If you wanna get with prefix; you can do;
byte b = 0xF2;
Console.WriteLine("0x{0}", b.ToString("X")); //0xF2

How come C# integer input doesn't accept the correct value?

I've recently started to code in C#, so I'm just learning the basics right now. I've tried to search for this through Google and on this site, however, I couldn't find any solutions, but basically when I do Console.Read(), and take in an input and store it into an integer variable, the value I input is strangely different when it is outputted.
Here is the block of code I am trying to run:
Console.WriteLine("Welcome To The Program!");
Console.Write("Enter the radius of the sun: ");
input = Console.Read();
Console.WriteLine(input);
Console.ReadKey();
Input is a type of int and when I type in say 5, it will output 53. If I input 0, it will output 48.
Can anyone please explain why this may be happening? I know there is a way to parse input by first taking it as a string input and then parsing it as an integer, but that would take too long for larger pieces of code.
Put it inside Convert.ToInt32 since you are reading the line as string value like this:
input = Convert.ToInt32(Console.Read());
For the record, the reason this didn't work is because Console.Read returns the ASCII integer representation of the first character entered in the console. The reason that "5" echoed 53 to the screen is this:
Console.Read begins reading from the console's In stream.
The first character in the stream is '5'.
The ASCII value of '5' is 53.
"input" is assigned the value of 53.
This should solve your problem:
input = int.Parse(Console.ReadLine());
You can also better use this:
int number;
if(!int.TryParse(Console.ReadLine(), out number)){
Console.WriteLine("Input was not an integer.");
return;
}
Console.WriteLine(number);
You are receiving the ASCII value of the character in question. In order to get what you want, you have to accept a string and then parse it. It will take less time than you think.
If you only want to read one character at a time, then you can use the following:
int input = int.Parse(((char)Console.Read()).ToString());
This gets the character of the code point and then turns it into a string before it is parsed. However, if you are going to have more than one character or there is any chance that the input won't be a number, then you should look at HeshamERAQI's response.

int.Parse() with leading zeros

How do I prevent the code below from throwing a FormatException. I'd like to be able to parse strings with a leading zero into ints. Is there a clean way to do this?
string value = "01";
int i = int.Parse(value);
Your code runs for me, without a FormatException (once you capitalize the method properly):
string value = "01";
int i = int.Parse(value);
But this does ring an old bell; a problem I had years ago, which Microsoft accepted as a bug against localization components of Windows (not .NET). To test whether you're seeing this, run this code and let us know whether you get a FormatException:
string value = "0"; // just a zero
int i = int.Parse(value);
EDIT: here's my post from Usenet, from back in 2007. See if the symptoms match yours.
For reference, here's what we found.
The affected machine had bad data for
the registry value
[HKEY_CURRENT_USER\Control Panel
\International\sPositiveSign].
Normally, this value is an empty
REG_SZ (null-terminated string). In
this case, the string was missing its
terminator. This confused the API
function GetLocaleInfoW(), causing it
to think that '0' (ASCII number zero)
was the positive sign for the current
locale (it should normally be '+').
This caused all kinds of havoc.
You can verify this for yourself with
regedit.exe: open that reg value by
right-clicking on the value and
selecting 'Modify Binary Data'. You
should see two dots on the right
(representing the null terminator).
If you see no dots, you're affected.
Fix it by adding a terminator (four
zeros).
You can also check the value of
CultureInfo.CurrentCulture.NumberFormat.PositiveSign;
it should be '+'.
It's a bug in the Windows localization
API, not the class libs. The reg
value needs to be checked for a
terminator. They're looking at it.
...and here's a report on Microsoft Connect about the issue:
Try
int i = Int32.Parse(value, NumberStyles.Any);
int i = int.parse(value.TrimStart('0'));
TryParse will allow you to confirm the result of the parse without throwing an exception. To quote MSDN
Converts the string representation of
a number to its 32-bit signed integer
equivalent. A return value indicates
whether the operation succeeded.
To use their example
private static void TryToParse(string value)
{
int number;
bool result = Int32.TryParse(value, out number);
if (result)
{
Console.WriteLine("Converted '{0}' to {1}.", value, number);
}
else
{
if (value == null) value = "";
Console.WriteLine("Attempted conversion of '{0}' failed.", value);
}
}
You don't have to do anything at all. Adding leading zeroes does not cause a FormatException.
To be 100% sure I tried your code, and after correcting parse to Parse it runs just fine and doesn't throw any exception.
Obviously you are not showing actual code that you are using, so it's impossible to say where the problem is, but it's definitely not a problem for the Parse method to handle leading zeroes.
Try
int i = Convert.ToInt32(value);
Edit: Hmm. As pointed out, it's just wrapping Int32.Parse. Not sure why you're getting the FormatException, regardless.
I have the following codes that may be helpful:
int i = int.Parse(value.Trim().Length > 1 ?
value.TrimStart(new char[] {'0'}) : value.Trim());
This will trim off all extra leading 0s and avoid the case of only one 0.
For a decimal number:
Convert.ToInt32("01", 10);
// 1
For a 16 bit numbers, where leading zeros are common:
Convert.ToInt32("00000000ff", 16);
// 255

Categories