Advanced parsing using Int.TryParse in C#

You have probably used the int.TryParse
method with this signature:
1 |
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">bool</span></span> TryParse <span class="token punctuation">(</span><span class="token class-name"><span class="token keyword">string</span><span class="token punctuation">?</span></span> s<span class="token punctuation">,</span> <span class="token keyword">out</span> <span class="token class-name"><span class="token keyword">int</span></span> result<span class="token punctuation">)</span><span class="token punctuation">;</span> |
That C# method accepts a string, s
, which, if it can be parsed, will be converted to an int
value and whose integer value will be stored in the result
parameter; at the same time, the method returns true
to notify that the parsing was successful.
As an example, this snippet:
1 2 3 4 5 |
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">.</span><span class="token function">TryParse</span><span class="token punctuation">(</span><span class="token string">"100"</span><span class="token punctuation">,</span> <span class="token keyword">out</span> <span class="token class-name"><span class="token keyword">int</span></span> result<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span>result <span class="token operator">+</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token string">"Failed"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
prints 102.
Does it work? Yes. Is this the best we can do? No!
How to parse complex strings with int.TryParse
What if you wanted to parse 100€? There is a less-known overload that does the job:
1 |
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token return-type class-name"><span class="token keyword">bool</span></span> TryParse <span class="token punctuation">(</span> <span class="token class-name"><span class="token keyword">string</span><span class="token punctuation">?</span></span> s<span class="token punctuation">,</span> <span class="token class-name">System<span class="token punctuation">.</span>Globalization<span class="token punctuation">.</span>NumberStyles</span> style<span class="token punctuation">,</span> <span class="token class-name">IFormatProvider<span class="token punctuation">?</span></span> provider<span class="token punctuation">,</span> <span class="token keyword">out</span> <span class="token class-name"><span class="token keyword">int</span></span> result<span class="token punctuation">)</span><span class="token punctuation">;</span> |
As you see, we have two more parameters: style
and provider
.
IFormatProvider? provider
allows you to specify the culture information: examples are CultureInfo.InvariantCulture
and new CultureInfo("es-es")
.
But the real king of this overload is the style
parameter: it is a Flagged Enum which allows you to specify the expected string format.
style
is of type System.Globalization.NumberStyles
, which has several values:
1 2 3 4 |
<span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Flags</span></span><span class="token punctuation">]</span> <span class="token keyword">public</span> <span class="token keyword">enum</span> <span class="token class-name">NumberStyles</span> <span class="token punctuation">{</span> None <span class="token operator">=</span> <span class="token number">0x0</span><span class="token punctuation">,</span> AllowLeadingWhite <span class="token operator">=</span> <span class="token number">0x1</span><span class="token punctuation">,</span> AllowTrailingWhite <span class="token operator">=</span> <span class="token number">0x2</span><span class="token punctuation">,</span> AllowLeadingSign <span class="token operator">=</span> <span class="token number">0x4</span><span class="token punctuation">,</span> AllowTrailingSign <span class="token operator">=</span> <span class="token number">0x8</span><span class="token punctuation">,</span> AllowParentheses <span class="token operator">=</span> <span class="token number">0x10</span><span class="token punctuation">,</span> AllowDecimalPoint <span class="token operator">=</span> <span class="token number">0x20</span><span class="token punctuation">,</span> AllowThousands <span class="token operator">=</span> <span class="token number">0x40</span><span class="token punctuation">,</span> AllowExponent <span class="token operator">=</span> <span class="token number">0x80</span><span class="token punctuation">,</span> AllowCurrencySymbol <span class="token operator">=</span> <span class="token number">0x100</span><span class="token punctuation">,</span> AllowHexSpecifier <span class="token operator">=</span> <span class="token number">0x200</span><span class="token punctuation">,</span> Integer <span class="token operator">=</span> <span class="token number">0x7</span><span class="token punctuation">,</span> HexNumber <span class="token operator">=</span> <span class="token number">0x203</span><span class="token punctuation">,</span> Number <span class="token operator">=</span> <span class="token number">0x6F</span><span class="token punctuation">,</span> Float <span class="token operator">=</span> <span class="token number">0xA7</span><span class="token punctuation">,</span> Currency <span class="token operator">=</span> <span class="token number">0x17F</span><span class="token punctuation">,</span> Any <span class="token operator">=</span> <span class="token number">0x1FF</span> <span class="token punctuation">}</span> |
You can combine those values with the |
symbol.
Let’s see some examples.
Parse as integer
The simplest example is to parse a simple integer:
1 2 3 4 |
<span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Fact</span></span><span class="token punctuation">]</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">CanParseInteger</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">NumberStyles</span> style <span class="token operator">=</span> NumberStyles<span class="token punctuation">.</span>Integer<span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> canParse <span class="token operator">=</span> <span class="token keyword">int</span><span class="token punctuation">.</span><span class="token function">TryParse</span><span class="token punctuation">(</span><span class="token string">"100"</span><span class="token punctuation">,</span> style<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">CultureInfo</span><span class="token punctuation">(</span><span class="token string">"it-it"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">out</span> <span class="token class-name"><span class="token keyword">int</span></span> result<span class="token punctuation">)</span><span class="token punctuation">;</span> Assert<span class="token punctuation">.</span><span class="token function">True</span><span class="token punctuation">(</span>canParse<span class="token punctuation">)</span><span class="token punctuation">;</span> Assert<span class="token punctuation">.</span><span class="token function">Equal</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Notice the NumberStyles style = NumberStyles.Integer;
, used as a baseline.
Parse parenthesis as negative numbers
In some cases, parenthesis around a number indicates that the number is negative. So (100) is another way of writing -100.
In this case, you can use the NumberStyles.AllowParentheses
flag.
1 2 3 4 |
<span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Fact</span></span><span class="token punctuation">]</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">ParseParenthesisAsNegativeNumber</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">NumberStyles</span> style <span class="token operator">=</span> NumberStyles<span class="token punctuation">.</span>Integer <span class="token operator">|</span> NumberStyles<span class="token punctuation">.</span>AllowParentheses<span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> canParse <span class="token operator">=</span> <span class="token keyword">int</span><span class="token punctuation">.</span><span class="token function">TryParse</span><span class="token punctuation">(</span><span class="token string">"(100)"</span><span class="token punctuation">,</span> style<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">CultureInfo</span><span class="token punctuation">(</span><span class="token string">"it-it"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">out</span> <span class="token class-name"><span class="token keyword">int</span></span> result<span class="token punctuation">)</span><span class="token punctuation">;</span> Assert<span class="token punctuation">.</span><span class="token function">True</span><span class="token punctuation">(</span>canParse<span class="token punctuation">)</span><span class="token punctuation">;</span> Assert<span class="token punctuation">.</span><span class="token function">Equal</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">100</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Parse with currency
And if the string represents a currency? You can use NumberStyles.AllowCurrencySymbol
.
1 2 3 4 5 |
<span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Fact</span></span><span class="token punctuation">]</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">ParseNumberAsCurrency</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">NumberStyles</span> style <span class="token operator">=</span> NumberStyles<span class="token punctuation">.</span>Integer <span class="token operator">|</span> NumberStyles<span class="token punctuation">.</span>AllowCurrencySymbol<span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> canParse <span class="token operator">=</span> <span class="token keyword">int</span><span class="token punctuation">.</span><span class="token function">TryParse</span><span class="token punctuation">(</span> <span class="token string">"100€"</span><span class="token punctuation">,</span> style<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">CultureInfo</span><span class="token punctuation">(</span><span class="token string">"it-it"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">out</span> <span class="token class-name"><span class="token keyword">int</span></span> result<span class="token punctuation">)</span><span class="token punctuation">;</span> Assert<span class="token punctuation">.</span><span class="token function">True</span><span class="token punctuation">(</span>canParse<span class="token punctuation">)</span><span class="token punctuation">;</span> Assert<span class="token punctuation">.</span><span class="token function">Equal</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
But, remember: the only valid symbol is the one related to the CultureInfo
instance you are passing to the method.
Both
1 |
<span class="token class-name"><span class="token keyword">var</span></span> canParse <span class="token operator">=</span> <span class="token keyword">int</span><span class="token punctuation">.</span><span class="token function">TryParse</span><span class="token punctuation">(</span> <span class="token string">"100€"</span><span class="token punctuation">,</span> style<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">CultureInfo</span><span class="token punctuation">(</span><span class="token string">"en-gb"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">out</span> <span class="token class-name"><span class="token keyword">int</span></span> result<span class="token punctuation">)</span><span class="token punctuation">;</span> |
and
1 |
<span class="token class-name"><span class="token keyword">var</span></span> canParse <span class="token operator">=</span> <span class="token keyword">int</span><span class="token punctuation">.</span><span class="token function">TryParse</span><span class="token punctuation">(</span> <span class="token string">"100$"</span><span class="token punctuation">,</span> style<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">CultureInfo</span><span class="token punctuation">(</span><span class="token string">"it-it"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">out</span> <span class="token class-name"><span class="token keyword">int</span></span> result<span class="token punctuation">)</span><span class="token punctuation">;</span> |
are not valid. One because we are using English culture to parse Euros, the other because we are using Italian culture to parse Dollars.
Hint: how to get the currency symbol given a CultureInfo? You can use NumberFormat.CurrecySymbol
, like this:
1 |
<span class="token keyword">new</span> <span class="token constructor-invocation class-name">CultureInfo</span><span class="token punctuation">(</span><span class="token string">"it-it"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>NumberFormat<span class="token punctuation">.</span>CurrencySymbol<span class="token punctuation">;</span> |
Parse with thousands separator
And what to do when the string contains the separator for thousands? 10.000 is a valid number, in the Italian notation.
Well, you can specify the NumberStyles.AllowThousands
flag.
1 2 3 4 |
<span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Fact</span></span><span class="token punctuation">]</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">ParseThousands</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">NumberStyles</span> style <span class="token operator">=</span> NumberStyles<span class="token punctuation">.</span>Integer <span class="token operator">|</span> NumberStyles<span class="token punctuation">.</span>AllowThousands<span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> canParse <span class="token operator">=</span> <span class="token keyword">int</span><span class="token punctuation">.</span><span class="token function">TryParse</span><span class="token punctuation">(</span><span class="token string">"10.000"</span><span class="token punctuation">,</span> style<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">CultureInfo</span><span class="token punctuation">(</span><span class="token string">"it-it"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">out</span> <span class="token class-name"><span class="token keyword">int</span></span> result<span class="token punctuation">)</span><span class="token punctuation">;</span> Assert<span class="token punctuation">.</span><span class="token function">True</span><span class="token punctuation">(</span>canParse<span class="token punctuation">)</span><span class="token punctuation">;</span> Assert<span class="token punctuation">.</span><span class="token function">Equal</span><span class="token punctuation">(</span><span class="token number">10000</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Parse hexadecimal values
It’s a rare case, but it may happen: you receive a string in the Hexadecimal notation, but you need to parse it as an integer.
In this case, NumberStyles.AllowHexSpecifier
is the correct flag.
1 2 3 4 |
<span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Fact</span></span><span class="token punctuation">]</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">ParseHexValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">NumberStyles</span> style <span class="token operator">=</span> NumberStyles<span class="token punctuation">.</span>AllowHexSpecifier<span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> canParse <span class="token operator">=</span> <span class="token keyword">int</span><span class="token punctuation">.</span><span class="token function">TryParse</span><span class="token punctuation">(</span><span class="token string">"F"</span><span class="token punctuation">,</span> style<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">CultureInfo</span><span class="token punctuation">(</span><span class="token string">"it-it"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">out</span> <span class="token class-name"><span class="token keyword">int</span></span> result<span class="token punctuation">)</span><span class="token punctuation">;</span> Assert<span class="token punctuation">.</span><span class="token function">True</span><span class="token punctuation">(</span>canParse<span class="token punctuation">)</span><span class="token punctuation">;</span> Assert<span class="token punctuation">.</span><span class="token function">Equal</span><span class="token punctuation">(</span><span class="token number">15</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Notice that the input string does not contain the Hexadecimal prefix.
Use multiple flags
You can compose multiple Flagged Enums to create a new value that represents the union of the specified values.
We can use this capability to parse, for example, a currency that contains the thousands separator:
1 2 3 4 |
<span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Fact</span></span><span class="token punctuation">]</span> <span class="token return-type class-name"><span class="token keyword">void</span></span> <span class="token function">ParseThousandsCurrency</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">NumberStyles</span> style <span class="token operator">=</span> NumberStyles<span class="token punctuation">.</span>Integer <span class="token operator">|</span> NumberStyles<span class="token punctuation">.</span>AllowThousands <span class="token operator">|</span> NumberStyles<span class="token punctuation">.</span>AllowCurrencySymbol<span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword">var</span></span> canParse <span class="token operator">=</span> <span class="token keyword">int</span><span class="token punctuation">.</span><span class="token function">TryParse</span><span class="token punctuation">(</span><span class="token string">"10.000€"</span><span class="token punctuation">,</span> style<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token constructor-invocation class-name">CultureInfo</span><span class="token punctuation">(</span><span class="token string">"it-it"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">out</span> <span class="token class-name"><span class="token keyword">int</span></span> result<span class="token punctuation">)</span><span class="token punctuation">;</span> Assert<span class="token punctuation">.</span><span class="token function">True</span><span class="token punctuation">(</span>canParse<span class="token punctuation">)</span><span class="token punctuation">;</span> Assert<span class="token punctuation">.</span><span class="token function">Equal</span><span class="token punctuation">(</span><span class="token number">10000</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
NumberStyles.AllowThousands | NumberStyles.AllowCurrencySymbol
does the trick.
Conclusion
We all use the simple int.TryParse
method, but when parsing the input string requires more complex calculations, we can rely on those overloads. Of course, if it’s still not enough, you should create your custom parsers (or, as a simpler approach, you can use regular expressions).
Are there any methods that have overloads that nobody uses? Share them in the comments!
Happy coding!
🐧
Source: https://www.code4it.dev/blog/advanced-int-tryparse