I have an array element that I am trying to replace all the numbers with letters. This is the array element before manipulation:
$a[0].object
--- OUTPUT ---
518773112
I convert the number to a string and store it in $e
. Then I find the length of that string and store that in $d
$e = $a[0].object.ToString()
$d = $a[0].object.ToString().length
$e
$d
---OUTPUT---
518773112
9
Then I try to looping through the string to replace the numbers with letters. I place $i
in the Substring to get the number that I'm trying to replace. Then I use an if-statement
to see if that substring is equal to a number, and if so, then I use the replace method to try and replace the number with a letter.
for($i=0; $i -lt $d; $i ){
$pos = $e.Substring($i,1)
if($pos -eq '0'){$e = $pos.replace('0', 'A')}
if($pos -eq '1'){$e = $pos.replace('1', 'B')}
if($pos -eq '2'){$e = $pos.replace('2', 'C')}
if($pos -eq '3'){$e = $pos.replace('3', 'D')}
if($pos -eq '4'){$e = $pos.replace('4', 'E')}
if($pos -eq '5'){$e = $pos.replace('5', 'F')}
if($pos -eq '6'){$e = $pos.replace('6', 'G')}
if($pos -eq '7'){$e = $pos.replace('7', 'H')}
if($pos -eq '8'){$e = $pos.replace('8', 'I')}
if($pos -eq '9'){$e = $pos.replace('9', 'J')}
}
My issue though, is it will concatenate the letters to the end of the number string:
518773112FBIHHDBBC
Likely, because I have =
in my then
portion of my if-statement
. However, when I replace =
with =
I get an error with my Substring method saying:
Exception calling "Substring" with "2" argument(s): "startIndex cannot be larger than length of string.
I've checked $i
and $d
and they are set correctly before I run the loop. So, I'm a little confused. What am I missing?
CodePudding user response:
To add a concise alternative to the existing, helpful answers, via a single, regex-based -replace
operation:
# PowerShell (Core) 7 only.
# -> 'FBIHHDBBC'
'518773112' -replace '\d', { [char] ([int] [char] 'A' [int] $_.Value) }
# Windows PowerShell alternative:
# (requires direct use of underlying .NET APIs)
[regex]::Replace('518773112', '\d', { param($m) [char] ([int] [char] 'A' [int] $m.Value) })
Regex escape sequence
\d
matches any single decimal digit.[int] [char] 'A' [int] $_.Value
adds the value of the captured digit ($_.Value
) as an integer to the integer representation of characterA
, i.e. it adds an offset to the Unicode code point ofA
.The resulting code point is then re-converted to a character (
[char]
), which yields the letter of interest.
As for what you tried:
Leaving the inefficiency of your approach aside, the problem was that you tried to build your result string in the same variable as the input string:
=
therefore appended the desired result to the input string- Just
=
essentially replaced the input string with the single character being processed, causing subsequent.Substring()
calls to fail, given that the string was now reduced to a single character.
The immediate fix would have been to build the result in a new variable (but note that all the solutions presented in the answers here a preferable):
$e = '518773112'
$d = $e.Length
$result = '' # initialize result string
for($i=0; $i -lt $d; $i ){
$pos = $e.Substring($i,1)
# Use = on *$result*
if($pos -eq '0'){$result = $pos.replace('0', 'A')}
if($pos -eq '1'){$result = $pos.replace('1', 'B')}
if($pos -eq '2'){$result = $pos.replace('2', 'C')}
if($pos -eq '3'){$result = $pos.replace('3', 'D')}
if($pos -eq '4'){$result = $pos.replace('4', 'E')}
if($pos -eq '5'){$result = $pos.replace('5', 'F')}
if($pos -eq '6'){$result = $pos.replace('6', 'G')}
if($pos -eq '7'){$result = $pos.replace('7', 'H')}
if($pos -eq '8'){$result = $pos.replace('8', 'I')}
if($pos -eq '9'){$result = $pos.replace('9', 'J')}
}
$result # Output the result: -> 'FBIHHDBBC'
CodePudding user response:
The String.Replace()
method will replace any matching character or substring for you, you don't need to handle (or even care about) each position in the string separately:
$e = '518773112'
foreach($digit in 0..9){
# calculate next letter character
$substitute = ($digit 'A'[0]) -as [char]
# replace all instances of $digit with $substitute
$e = $e.Replace("$digit", $substitute)
}
The value of $e
is now "FBIHHDBBC"
CodePudding user response:
Here's my two cents:
-join ('518773112' -split '(.)' -ne '' | Foreach-Object { [char]([int]$_ 65)})
Result:
FBIHHDBBC
Alternative with Select-Object
:
-join ('518773112' -split '(.)' -ne '' | Select-Object @{Name = 'Chr'; Expression = {[char]([int]$_ 65)}}).Chr
CodePudding user response:
Another concise one (inspired by Theo's helpful answer):
-join '518773112'.ToCharArray().ForEach{[char]([int]$_ 17)}
This converts the input string into a char array, then loops over each character using PowerShell's intrinsic method ForEach
.
In the script block of ForEach
the code point of the character is incremented to be in the range of numeric digits '0'
..'9'
, then converted back into a character. The "magic" number 17
is just the difference between the code points of characters 'A'
and '0'
(i. e. [int][char]'A' - [int][char]'0'
outputs 17
).
Finally the unary form of the -join
operator is used to create a single string from the individual characters.
CodePudding user response:
$e
will showed like concatenated , it's because you connect the $e
through the loop.
The function subString
return a copy of $e
that subed.
you should declare a new varibel ,
$a[0] = 518773112;
$e = $a[0].ToString()
$d = $a[0].ToString().length
$str = ""
for($i=0; $i -lt $d; $i ){
$pos = $e.Substring($i,1)
if($pos -eq '0'){$str = $pos.replace('0', 'A')}
if($pos -eq '1'){$str = $pos.replace('1', 'B')}
if($pos -eq '2'){$str = $pos.replace('2', 'C')}
if($pos -eq '3'){$str = $pos.replace('3', 'D')}
if($pos -eq '4'){$str = $pos.replace('4', 'E')}
if($pos -eq '5'){$str = $pos.replace('5', 'F')}
if($pos -eq '6'){$str = $pos.replace('6', 'G')}
if($pos -eq '7'){$str = $pos.replace('7', 'H')}
if($pos -eq '8'){$str = $pos.replace('8', 'I')}
if($pos -eq '9'){$str = $pos.replace('9', 'J')}
}
Write-Output $str;
although there are better ways to do the same job
CodePudding user response:
Note, this example assumes the values are only integers.
Here is one way how you can approach this, first generate a charset from A
to J
then split the value of the .object
property to generate an array of these numbers which then we can use for indexing on the charset:
$char = [char[]]([char]'A'..[char]'J')
$a = [pscustomobject]@{
object = 518773112
}
$transform = $a.object.ToString() -split '' -ne ''
$a.object = [string]::new($char[$transform])
The result should be:
PS /> $a
object
------
FBIHHDBBC