Lazy Diary @ Hatena Blog

PowerShell / Java / miscellaneous things about software development, Tips & Gochas. CC BY-SA 4.0/Apache License 2.0

tr equivalent in PowerShell (Unicode surrogate pair-aware)

There is no straightforward tr equivalent in Windows, so I made an cmdlet that you can use like tr command. This tr cmdlet is aware of Unicode characters including surrogate pairs.

function tr {
  Param(
    [Parameter(ValueFromPipeline=$true,Mandatory=$true)]
    [string] $TargetString,
    [Parameter(Mandatory=$true)]
    [string] $FromString,
    [Parameter(Mandatory=$true)]
    [string] $ToString
  )
  begin {
    # [-split ""] splits a surrogate pair into two invalid characters,
    # so the code below is not suitable for this purpose
    # $FromStringArray = $FromString -split "";
    # $FromStringArray = $FromStringArray[1..($FromStringArray.length-2)];

    # Split string into character array
    $FromStringArray = @();
    $FromStringBytes = [Text.Encoding]::UTF32.GetBytes($FromString);
    for ($i=0; $i -lt $FromStringBytes.length; $i+=4) {
         $FromStringArray += [Text.Encoding]::UTF32.GetString($FromStringBytes, $i, 4);
    }

    $ToStringArray = @();
    $ToStringBytes = [Text.Encoding]::UTF32.GetBytes($ToString);
    for ($i=0; $i -lt $ToStringBytes.length; $i+=4) {
         $ToStringArray += [Text.Encoding]::UTF32.GetString($ToStringBytes, $i, 4);
    }
  }
  process {
    for ($i=0; $i -lt $FromStringArray.Length -and $i -lt $ToStringArray.Length; $i++) {
        $TargetString = $TargetString.Replace($FromStringArray[$i],$ToStringArray[$i]);
    }
    $TargetString
  }
}

ex:

PS > @("𩸽𠀋", "あいうえおあお") | tr -FromString "𩸽𠀋うえお" -ToString "○𡶷ウエオ"

○𡶷
あいウエオあオ