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

経緯

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

環境

クライアント環境

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

テスト方法

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

$data = "2018年09月26日水曜日の沖縄の天気は曇り時々晴れ、
最高気温は31℃、最低気温は26℃の予想です。"

コード

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

$data = "2018年09月26日水曜日の沖縄の天気は曇り時々晴れ、
最高気温は31℃、最低気温は26℃の予想です。"

Measure-Command {

    for($i = 0; $i -lt 1000000; $i++) {
        [void]$data.Replace('0', '0').Replace('1', '1').Replace('2', '2').Replace('3', '3').Replace('4', '4').Replace('5', '5').Replace('6', '6').Replace('7', '7').Replace('8', '8').Replace('9', '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 演算子

$data = "2018年09月26日水曜日の沖縄の天気は曇り時々晴れ、
最高気温は31℃、最低気温は26℃の予想です。"

Measure-Command {

    for($i = 0; $i -lt 1000000; $i++) {
        [void]$data -replace "0" , "0" -replace "1", "1" -replace "2", "2" -replace "3", "3" -replace "4", "4" -replace "5", "5" -replace "6" , "6" -replace "7", "7" -replace "8", "8" -replace "9", "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

$data = "2018年09月26日水曜日の沖縄の天気は曇り時々晴れ、
最高気温は31℃、最低気温は26℃の予想です。"

Measure-Command {

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

public class Helper
{
    public string DatetimeChar2Han(string str)
    {
        try {
            return str.Replace('0', '0').Replace('1', '1').Replace('2', '2').Replace('3', '3').Replace('4', '4').Replace('5', '5').Replace('6', '6').Replace('7', '7').Replace('8', '8').Replace('9', '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 (実は今回このパターンでやった)

$data = "2018年09月26日水曜日の沖縄の天気は曇り時々晴れ、
最高気温は31℃、最低気温は26℃の予想です。"

Measure-Command {

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

public class Helper
{
    public string[] convertFrom = new string[] {"0","1","2","3","4","5","6","7","8","9"};
    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 メソッドを使うのが吉かも