関数

PowerShellと.NET Frameworkを使用して、ファイルの文字コードを高精度に判別する関数を作成しました。UTF-8、Shift_JIS、EUC-JPに対応しています。

function Get-FileEncoding {
    param(
        [Parameter(Mandatory=$true)]
        [string]$Path
    )

    # ファイルが存在するかチェック
    if (-not (Test-Path $Path)) {
        throw "ファイルが見つかりません: $Path"
    }

    # ファイルサイズが0の場合
    if ((Get-Item $Path).Length -eq 0) {
        return "空のファイルです"
    }

    # ファイルをバイナリモードで開く
    $bytes = [System.IO.File]::ReadAllBytes($Path)

    # バイナリファイルかテキストファイルかを判別
    function IsBinaryFile($bytes) {
        # バイト配列のうち、制御文字以外の割合を計算
        $nonTextChars = $bytes | Where-Object { $_ -lt 0x07 -or ($_ -gt 0x0D -and $_ -lt 0x20) }
        $nonTextRatio = $nonTextChars.Count / $bytes.Length

        # 非テキスト文字が30%以上ならバイナリファイルとみなす
        return $nonTextRatio -gt 0.3
    }

    if (IsBinaryFile $bytes) {
        return "バイナリファイルです"
    }

    # BOMのチェック
    $bomEncodings = @{
        ([byte[]](0x00,0x00,0xFE,0xFF)) = "UTF-32 BE";
        ([byte[]](0xFF,0xFE,0x00,0x00)) = "UTF-32 LE";
        ([byte[]](0xFE,0xFF))           = "UTF-16 BE";
        ([byte[]](0xFF,0xFE))           = "UTF-16 LE";
        ([byte[]](0xEF,0xBB,0xBF))      = "UTF-8 with BOM";
    }

    foreach ($bom in $bomEncodings.Keys) {
        $bomLength = $bom.Length
        if ($bytes.Length -ge $bomLength) {
            $fileBom = $bytes[0..($bomLength - 1)]
            if ($fileBom -eq $bom) {
                return $bomEncodings[$bom]
            }
        }
    }

    # サポートするエンコーディングのリスト
    $encodings = @(
        [System.Text.Encoding]::UTF8,
        [System.Text.Encoding]::GetEncoding("Shift_JIS"),
        [System.Text.Encoding]::GetEncoding("EUC-JP"),
        [System.Text.Encoding]::Unicode,      # UTF-16 LE
        [System.Text.Encoding]::BigEndianUnicode, # UTF-16 BE
        [System.Text.Encoding]::UTF32
    )

    # エンコーディングを試行
    foreach ($encoding in $encodings) {
        $decoder = [System.Text.Encoding]($encoding.Clone())
        $decoder.DecoderFallback = New-Object System.Text.DecoderExceptionFallback

        try {
            [void]$decoder.GetString($bytes)
            return $encoding.EncodingName
        } catch {
            # 次のエンコーディングを試す
        }
    }

    return "エンコーディングを判別できませんでした"
}

使用方法

$encoding = Get-FileEncoding -Path "ファイルのパス.txt"
Write-Host "ファイルのエンコーディングは: $encoding"

説明

バイナリファイルの判別

BOM(Byte Order Mark)のチェック

エンコーディングの判別

注意点