Reputation: 1107
I'm attempting to convert a string to an integer using PowerShell. However, it keeps on telling me that I don't have a valid number, even though I'm sure I do.
First of all, here's how I'm getting my variable, and a printout of the type, etc. just to ensure validity:
$obj = (New-Object -TypeName PSCustomObject -Property @{
LastSaved = $com.GetDetailsOf($_, 155).toString().trim()
})
Write-Host $obj.LastSaved
$datePart,$b,$c = $obj.LastSaved.Split(" ")
Write-Host $datePart
$intVar,$b,$c = $datePart.Split("/")
$intVar = $intVar.Trim()
$intVar -replace '\W', ''
Write-Host $intVar
Write-Host $intVar.GetType()
The output:
5/26/2016 8:09 AM
5/26/2016
5
System.String
Here's the first method I've tried for conversion:
[int]$converted = 0
[int]::TryParse($intVar, [ref]$converted)
Write-Host $converted
And the output:
False
0
Next method:
$converted = [convert]::ToInt32($intVar, 10)
And the result:
Exception calling "ToInt32" with "2" argument(s): "Could not find any recognizable digits."
And the third method I've tried:
$converted = $intVar / 1
And the result:
Cannot convert value "5" to type "System.Int32". Error: "Input string was not in a correct format."
If I manually assign $intVar
a value of "5" ($intVar = "5"
) everything works just fine, so I think there must be an issue with how I'm getting the value. But I have no idea what I could be doing wrong, as the GetType()
says it is indeed a string.
EDIT: Per TobyU's answer, I've also tried $intVar = [int]$intVar
, with the same result of
Cannot convert value "5" to type "System.Int32". Error: "Input string was not in a correct format."
EDIT: Yet another method:
$intVar = [int]::Parse($intVar)
Which gives:
Exception calling "Parse" with "1" argument(s): "Input string was not in a correct format."
EDIT 3: So apparently, as some commenters mentioned, there are invalid characters. Here is the output of a Format-Hex
:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000 3F 32 36 ?26
Upvotes: 5
Views: 7753
Reputation: 360
The following code will work with strings as well as with numeric values. The idea is to first test and see if the value can be converted to [int], if yes, convert it, otherwise; leave it as is.
$Converted = '5'
If ([Int]::TryParse($Converted , [Ref] $Null))
{
$Converted = [Convert]::ToInt32($Converted)
Write-Host "Pass '$Converted' $($Converted.GetType())" -ForeGroundColor Green
} Else {
Write-Host "Fail '$Converted' $($Converted.GetType())" -ForeGroundColor Red
}
Upvotes: 0
Reputation: 437753
Examining the error messages in your question's source text reveals that your string contains the invisible LEFT-TO-RIGHT-MARK Unicode character (U+200E
), which is why the conversion fails.
Removing that character will make the conversion succeed, which in the simplest case is achieved by simply eliminating all non-digit chars. from the string:
# Simulate the input string with the invisible control char.
$intStr = [char] 0x200e + '5'
# FAILS, due to the invisible Unicode char.
[int] $intStr # -> ... "Input string was not in a correct format."
# OK - eliminate non-digits first.
# Note the required (...) for proper precedence.
[int] ($intStr -replace '\D') # -> 5
Optional reading: Examining a string's characters:
# Print the code points of the string's characters:
PS> [int[]] [char[]] $intStr
8206 # decimal equivalent of 0x200e, the LEFT-TO-RIGHT-MARK
53 # decimal equivalent of 0x54, the DIGIT FIVE
# Show the code points in hex. format and print the char.
PS> [char[]] $intStr |
Select-Object @{ n='CodePoint'; e={ 'U+{0}' -f ([int] $_).ToString('X4') } },
@{ n='Char'; e={ $_ } }
CodePoint Char
--------- ----
U+200E
U+0035 5
You can also use Format-Hex
, but the format isn't easy to parse visually:
PS> $intStr | Format-Hex -Encoding BigEndianUnicode
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000000000000000 20 0E 00 35 ..5
-Encoding BigEndianUnicode
(UTF16-BE) is used - even though .NET string use Unicode
(UTF16-LE) - so that the invariably byte-oriented display shows the high byte of the 16-bit code units first, which reads more naturally.
Byte pair 20 0E
is the first code unit, U+200E
(the left-to-right mark), and 00 35
the second one, U+0035
(the digit 5
).
The printed characters to the right are of limited usefulness, because they are the byte-individual interpretation of the input bytes, which only renders characters in the 8-bit range as expected (code points <= U+00FF
); a 0x0
byte is represented as a .
Upvotes: 4
Reputation: 3908
$intVar = [int]$intVar
should work just fine in this case.
$intVar.GetType() # String
$intVar = [int]$intVar
$intVar.GetType() # Int32
Upvotes: 0