oracle

Powershell でファイルの文字コードを判定する

Powershell 7.xの場合

以下をResolve-FileEncoding.ps1というファイル名で作成します。(ファイル名はお好みでどうぞ)BOM付UTF-8でファイル作成するとPowerShell 5.1xでもPowerShell 7.xでも動作します。

ソースプログラム
param (
    [Parameter(Mandatory = $true)]
    [string]$Path
)

function Test-Encoding {
    param (
        [byte[]]$bytes,
        [string]$encodingName
    )

    try {
        $enc = [System.Text.Encoding]::GetEncoding($encodingName)
        $utf8 = [System.Text.Encoding]::UTF8

        #バイト配列をエンコードに合わせてテキスト化
        $text = $enc.GetString($bytes)

        # 不正文字(U+FFFD, サロゲートペア)を含むか
        # Shift_JISとEUCには存在しない文字である
        if ($text -match '[\uFFFD\uD800-\uDFFF]') {
            return $false
        }

        # バイト配列に戻す(往復変換で一致するか)
        $reencoded = $enc.GetBytes($utf8.GetString($utf8.GetBytes($text)))
        # バイト配列の比較結果を true/falseで返却
        return [System.Linq.Enumerable]::SequenceEqual($reencoded, $bytes)
    } catch {
        return $false
    }
}

function Resolve-FileEncoding {
    param (
        [string]$Path
    )

    if (-not (Test-Path $Path)) {
        Write-Output "File not found: $Path"
        return
    }

    try {
        $maxBytes = 4096  # 4KBだけ読む
        # 読み取り専用で開く
        $fs = [System.IO.File]::OpenRead($Path)
        # バイト配列作成
        $bytes = New-Object byte[] $maxBytes
        # 配列にファイルを読み込み
        $readCount = $fs.Read($bytes, 0, $maxBytes)
        $fs.Close()

        # 実際に読めたサイズに合わせて切り詰め(4Kに満たないファイルを想定)
        # 切り詰めというより新たにエリアを確保してコピー
        $bytes = $bytes[0..($readCount - 1)]
    } catch {
        Write-Output "Failed to read file: $_"
        return
    }

    # BOMチェック
    if ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
        # BOM:EF BB BF  (UTF-8 with BOM)
        Write-Output "UTF-8 with BOM"
        return
    }
    elseif ($bytes.Length -ge 2 -and $bytes[0] -eq 0xFF -and $bytes[1] -eq 0xFE) {
        # BOM:FF FE (UTF-16 LE Little Endian)
        Write-Output "UTF-16 LE"
        return
    }
    elseif ($bytes.Length -ge 2 -and $bytes[0] -eq 0xFE -and $bytes[1] -eq 0xFF) {
        # BOM:FE FF (UTF-16 BE Big Endian)
        Write-Output "UTF-16 BE"
        return
    }

    # UTF-8 BOMなし判定(strict)
    $utf8Strict = [System.Text.UTF8Encoding]::new($false, $true)
    try {
        $utf8Strict.GetString($bytes) | Out-Null
        Write-Output "UTF-8 (no BOM)"
        return
    } catch {}

    # Shift_JIS 判定
    if (Test-Encoding $bytes "shift_jis") {
        Write-Output "Shift_JIS"
        return
    }

    # EUC-JP 判定
    if (Test-Encoding $bytes "euc-jp") {
        Write-Output "EUC-JP"
        return
    }

    Write-Output "Unknown encoding"
}

# --- 関数呼び出し ---
Resolve-FileEncoding -Path $Path

Version 5.xの場合はこちら

スポンサーリンク
タイトルとURLをコピーしました