PowerShell で全角数字を半角に置き換えるコードの実行時間を計測

[ブログからの転載](https://1bed.allright.life/?p=2780)

## 経緯

PowerShell を使ってデータ移行を行う時に、データ整備のために全角を半角にする... よくある話だと思いますが、先日仕事でその場面で色々調査する時間がなかったのでガーッとコーディングしましたが、「あれは遅いのでは？」と思って、サッと思い浮かぶ方法で計測してみました

## 環境

### クライアント環境

* Windows 10 Pro
* PowerShell 5.1.17134.228
* Surface Pro 4 (Core i5-6300U)

### テスト方法

次のデータの全角数字を半角数字に 1,000,000 回置き換える。

```powershell
$data = "２０１８年０９月２６日水曜日の沖縄の天気は曇り時々晴れ、
最高気温は３１℃、最低気温は２６℃の予想です。"
```

## コード

### 1. System.String の Replace メソッドを使う

```powershell
$data = "２０１８年０９月２６日水曜日の沖縄の天気は曇り時々晴れ、
最高気温は３１℃、最低気温は２６℃の予想です。"

Measure-Command {

    for($i = 0; $i -lt 1000000; $i++) {
        [void]$data.Replace('０', '0').Replace('１', '1').Replace('２', '2').Replace('３', '3').Replace('４', '4').Replace('５', '5').Replace('６', '6').Replace('７', '7').Replace('８', '8').Replace('９', '9')
    }

}

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 3
Milliseconds      : 799
Ticks             : 37996428
TotalDays         : 4.39773472222222E-05
TotalHours        : 0.00105545633333333
TotalMinutes      : 0.06332738
TotalSeconds      : 3.7996428
TotalMilliseconds : 3799.6428
```

### 2. PowerShell の -replace 演算子

```powershell
$data = "２０１８年０９月２６日水曜日の沖縄の天気は曇り時々晴れ、
最高気温は３１℃、最低気温は２６℃の予想です。"

Measure-Command {

    for($i = 0; $i -lt 1000000; $i++) {
        [void]$data -replace "０" , "0" -replace "１", "1" -replace "２", "2" -replace "３", "3" -replace "４", "4" -replace "５", "5" -replace "６" , "6" -replace "７", "7" -replace "８", "8" -replace "９", "9"
    }

}

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 6
Milliseconds      : 475
Ticks             : 64756627
TotalDays         : 7.49497997685185E-05
TotalHours        : 0.00179879519444444
TotalMinutes      : 0.107927711666667
TotalSeconds      : 6.4756627
TotalMilliseconds : 6475.6627
```

### 3. C# で置き換える1

```powershell
$data = "２０１８年０９月２６日水曜日の沖縄の天気は曇り時々晴れ、
最高気温は３１℃、最低気温は２６℃の予想です。"

Measure-Command {

# 半角を全角に変換する
Add-Type -Language CSharp -TypeDefinition @"
using System;

public class Helper
{
    public string DatetimeChar2Han(string str)
    {
        try {
            return str.Replace('０', '0').Replace('１', '1').Replace('２', '2').Replace('３', '3').Replace('４', '4').Replace('５', '5').Replace('６', '6').Replace('７', '7').Replace('８', '8').Replace('９', '9');
        } catch {
            return str;
        }
    }
}
"@
    $helper = [Helper]::new()

    for($i = 0; $i -lt 1000000; $i++) {
        [void]$helper.DatetimeChar2Han($data)
    }
}

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 3
Milliseconds      : 251
Ticks             : 32512049
TotalDays         : 3.76296863425926E-05
TotalHours        : 0.000903112472222222
TotalMinutes      : 0.0541867483333333
TotalSeconds      : 3.2512049
TotalMilliseconds : 3251.2049
```

### 4. C# で置き換える2 (実は今回このパターンでやった)

```powershell
$data = "２０１８年０９月２６日水曜日の沖縄の天気は曇り時々晴れ、
最高気温は３１℃、最低気温は２６℃の予想です。"

Measure-Command {

# 半角を全角に変換する
Add-Type -Language CSharp -TypeDefinition @"
using System;

public class Helper
{
    public string[] convertFrom = new string[] {"０","１","２","３","４","５","６","７","８","９"};
    public string[] convertTo   = new string[] {"0","1","2","3","4","5","6","7","8","9"};

    public string ZenNumber2Han(string str)
    {
        try {
            string buf = str;
            for(int i = 0; i < convertFrom.Length; i++) {
                buf = buf.Replace(convertFrom[i], convertTo[i]);
            }
            return buf;
        } catch {
            return str;
        }
    }
}
"@
    $helper = [Helper]::new()

    for($i = 0; $i -lt 1000000; $i++) {
        [void]$helper.ZenNumber2Han($data)
    }
}

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 4
Milliseconds      : 602
Ticks             : 46021738
TotalDays         : 5.3265900462963E-05
TotalHours        : 0.00127838161111111
TotalMinutes      : 0.0767028966666667
TotalSeconds      : 4.6021738
TotalMilliseconds : 4602.1738
```

## 考察

System.String の Replace メソッドを使うのが一番速く、且つ、C# のコードで書いたほうが速そう

PowerShell の -replace 演算子は、正規表現が使えるので一概に比べることはできないが、単純な置き換えなら System.String の Replace メソッドを使うのが吉かも