Home > database >  Replace numbers with letters - powershell
Replace numbers with letters - powershell

Time:04-22

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 character A, i.e. it adds an offset to the Unicode code point of A.

  • 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
  • Related