5

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             
7
  • I'd suggest using .Trim() on your string to remove any possible hidden characters before/after the integer. Commented Mar 5, 2019 at 15:37
  • @TheIncorrigible1 I've updated my code to try a .Trim() and -replace, with the same results (see my edit). Commented Mar 5, 2019 at 15:41
  • 2
    try sending it to Format-Hex to see what all is there. as others have mentioned, there is apparently something there that otta not be. Commented Mar 5, 2019 at 15:46
  • also consider trying -replace '[^\d]' (the second parameter is optional if you're just deleting) Commented Mar 5, 2019 at 15:47
  • @Lee_Dailey Ah, I didn't know about that method. I've updated the question with the hex output. Commented Mar 5, 2019 at 15:52

3 Answers 3

4

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 .

Sign up to request clarification or add additional context in comments.

3 Comments

@TastesLikeTurkey :) My pleasure; please see my update re examining a string's characters.
My goto for calculated properties is using @( @{ ... } ) with each hashtable on a newline.
@TheIncorrigible1 That gives you a lot of flexibility and allows you to omit the , between the elements (assuming you put them on separate lines), but my preference is to do without the enclosing @( ... ) and use , to terminate each element line for implicit line continuation - as now shown in the answer. (An individual hashtable can be spread across multiple lines either way).
0
$intVar = [int]$intVar

should work just fine in this case.

$intVar.GetType() # String
$intVar = [int]$intVar
$intVar.GetType() # Int32

3 Comments

This also gives me the error Cannot convert value "‎5" to type "System.Int32". Error: "Input string was not in a correct format."
Looks like there is a hidden character somewhere in your value.
I've updated my code to try a .Trim() and -replace, with the same results (see my edit)
0

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
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.