views:

460

answers:

11

Is there a better way of testing if a string can be converted to an integer other than something like the following?

Public Function IsInt(ByVal value As Object) As Boolean
    Try
        Dim temp As Integer = CInt(value)
        Return True
    Catch ex As Exception
        Return False
    End Try
End Function

by "better" I mean less verbose and/or w/o an exception.

TryParse would be the way to go, but I'm using the compact framework 2.0 and tryparse doesn't seem to be implemented....

Thanks anyways.

It seems that MarkJ is correct and the above seems to be functionally the same as IsNumeric, so I suppose that's my answer. I don't know why I thought CInt was more strict than IsNumeric. I guess it's better to test using CInt verses IsNumeric since that's the function I'm using to do the conversion?

+3  A: 

well if you want to avoid using exceptions you could match it against a regular expression that allows only digit characters before converting.

Brian Schroth
but then I'd have two problems! ;-)
Booji Boy
+14  A: 

Think you could use TryParse:

http://blogs.vbcity.com/xtab/archive/2006/03/25/5926.aspx

Paul
Good suggestion for full-blown .NET implementation, but won't work on Compact Framework.
John M Gant
Also TryParse applies different rules from CInt, and CInt was used in the original question. TryParse doesn't accept `.` or currency values, but CInt does. I guess it's for Booji Boy to decide what the rules need to be.
MarkJ
I believe IsNumeric allows these characters... Perhaps that is the answer?
Paul
+4  A: 

You can use the built in IsNumeric Function

Dim CanConvert as Boolean = IsNumeric(value)

http://msdn.microsoft.com/en-us/library/6cd3f6w1(VS.71).aspx

geoff
IsNumeric allows $ and . which can cause the casting to fail.
Booji Boy
In that case TryParse is the way to go
geoff
+1 @Booji Boy, you are incorrect. IsNumeric allows `.` and `$` but so does CInt (it rounds fractional values down). I've checked with the desktop framework - does the Compact framework do something different??
MarkJ
MarkJ, you are right! I didn't think cInt worked that way. What was I thinking? Thanks
Booji Boy
+3  A: 
Public Function IsInt(ByVal value As Object) As Boolean
    Dim i As Integer
    Return Integer.TryParse(Convert.ToString(value), i)
End Function
Joel Coehoorn
+1  A: 
Dim s as String = "23"
Dim i as Integer
If Int32.TryParse(s, i) Then
    ' String was a valid integer... '
End If
Shawn Simon
+3  A: 

you can use Integer.TryParse, which will return a bool indicating whether the conversion was successfull or not

Grizzly
+1  A: 

Use the TryParse shared method of the Integer type.

For example:

Private Function CanStringBeCastAsInteger(ByVal myString As String) As Boolean
    Dim myInt As Integer = 0
    Return Integer.TryParse(myString, myInt)
End Function

The benefit of using the TryParse method is that it avoids having to throw and subsequently catch an Exception when the cast fails. Throwing and catching exceptions is an expensive operation.

Not only will the TryParse method return a True/False result, telling you if the conversion will succeed or not, it will also return, in the myInt parameter in my example, the resulting conversion for you, all in one line of code.

CraigTP
A: 

You'd need to roll your own regex e.x.: Regex.IsMatch("4354354", "\d+"), and still include the try/catch block as a backup.

hjb417
-1, sorry, for a couple of reasons. Try/Catch is good as part of the application's error handling logic, but not simply as a backup in case the regex logic misses it. The regex for this is not so difficult that you can't be assured of its correctness. Also have to downvote because the regex in your example isn't adequate. "A123Z" would pass, and "-10" would fail.
John M Gant
+1  A: 

If you're only performing the conversion infrequently, what you have is fine (assuming there's no TryParse() available to you) - it's not going to affect performance.

If you're going to perform millions of conversions, and a large number of them might fail then the exception you're catching could be a perf issue (maybe).

If you can't use TryParse() probably the best thing to do (perf-wise) is to simply check each character in the string and if it's not a digit return false. Don't forget to account for a possible negative sign and group separators (if you want to support them).

Otherwise, parse the string to an int, which will succeed in 99% of the cases. you'll only get an exception if it won't fit. If you really want to avoid the exception that Parse() might generate, it's not hard to actually parse the sting of digits yourself, and return failure if it goes out of range.

Jon Skeet did a quick analysis of this back before the Framework contained TryParse():

None of this fixes the verbosity, though. but as long as it's a self-contained method, there's no real problem with a little verbosity.

Michael Burr
+1  A: 

Here is something very similar to what you have already but uses the Convert class instead of CType and does not use TryParse

    Public Function IsInt(ByVal value As Object) As Boolean
    Try
        Convert.ToInt32(value)
        Return True
    Catch ex As System.FormatException
        Return False
    End Try
End Function
DevByDefault
Why use the `Convert` class? There’s no advantage to it. In fact, the `Convert` class is quite superfluous (except when you need to represent a number in a base other than 10, and 16 which are the only bases supported by `ToString`).
Konrad Rudolph
+4  A: 

Since TryParse isn't supported on the Compact Framework, regex is your next best option.

The first example doesn't allow decimals. The second one does.

Regex.IsMatch(value, "^-?\d+$")
Regex.IsMatch(value, "^-?\d+(?:\.\d+)?$")

If you need to allow for scientific notation, you need to tweak it a little more. It really just isn't that bad. You've got the beginning of the string ^, an optional dash -?, one or more digits \d+, a non-capturing group (?:) that looks for a single decimal point \. and one or more digits \d+. Another ? to allow either zero or one instances of the non-capturing group, and then the end of the string $.

Edit: One thing I didn't think about before: this method is a little imprecise because you could get a really huge number that is numerically a valid integer but can't be converted to an Int32. If that's a possibility, you could constrain the number of characters. Instead of \d+, you could do \d{1,8}, for example.

John M Gant
+1 for another Compact Framework gotcha
Neil N
The method is also not regionally aware - some cultures use comma `,` for decimal delimiter not dot `.`
MarkJ
@MarkJ, good point.
John M Gant