マクロツイーター

はてダから移行した記事の表示が崩れてますが、そのうちに直せればいいのに(えっ)

Windows の ANSI コードページを知りたい話(2)

前回の続き)

PerlANSI コードページを知りたい

Win32 モジュールを使う

Win32 モジュールは Win32 API の(比較的)単純なラッパーである関数群を提供するもの。

use strict;
use Win32;
# ANSI コードページ
print("ANSI cp = ", Win32::GetACP(), "\n");
# OEM コードページ
print("OEM cp = ", Win32::GetOEMCP(), "\n");
# コンソール入力コードページ
print("console input cp = ", Win32::GetConsoleCP(), "\n"); 
# コンソール出力コードページ
print("console output cp = ", Win32::GetConsoleOutputCP(), "\n");

日本語版 Windows だと結果は全部「932」になる。

ANSI cp = 932
OEM cp = 932
console input cp = 932
console output cp = 932

エラー対策を考慮すると以下のようになる。

use strict;

## ansi_codepage()
# ANSIコードページの値を返す。失敗時およびWindowsでない場合は
# undefを返す。
sub ansi_codepage() {
  my ($ret);
  # Windowsでないならundef
  ($^O eq 'MSWin32') or return $ret;
  eval {
    # Win32モジュールは無いかもしれない
    require Win32;
    $ret = Win32::GetACP();
  };
  # 前のevalの成功時のみ値が返る
  return $ret;
}

print("ANSI cp = ", ansi_codepage(), "\n");
ANSI cp = 932
Encode::Locale モジュールを使う
use strict;
use Encode::Locale;

# 現在のロケールの文字コード
# WindowsではANSIコードページの文字コード(固定らしい)
print($Encode::Locale::ENCODING_LOCALE, "\n");
# コンソール入力コードページの文字コード
# Windows以外では ENCODING_LOCALE と同じになるらしい
print($Encode::Locale::ENCODING_CONSOLE_IN, "\n");
# コンソール出漁コードページの文字コード
# Windows以外では ENCODING_LOCALE と同じになるらしい
print($Encode::Locale::ENCODING_CONSOLE_OUT, "\n");

日本語版 Windows での実行結果は以下の通り。

cp932
cp932
cp932

Encode::Locale は Windows 専用ではない。(UTF-8 運用の)Linux では以下のような結果が得られる。

UTF-8
UTF-8
UTF-8

なお、Encode::Locale の主たる目的は、「Encode モジュールで使う文字コード'locale' を指定することで先述の ENCODING_LOCALE が使われるようにする」ことである。すなわち、前回に挙げたような、非 ASCII のファイル名を扱いたい場合には、このモジュールを読み込んで 'locale' 指定を使うと環境費依存で所望の処理が行える。

# 文字コードはUTF-8
use strict;
use utf8;
use Encode qw(encode);
use Encode::Locale;

my $f = 'アレ.txt'; # Unicode文字列
# 文字コード名を 'locale' にすると、ENCODING_LOCALE による
# バイト列に変換される
open(my $h, '>', encode('locale', $f)) or die;
print $h ("TeX\n");
close($h);

LuaANSI コードページを知りたい

Lua の場合、標準 C 関数の setlocale() の単純なラッパーである os.setlocale() という標準ライブラリ関数が用意されているので、これを利用して ANSI コードページを取得できる。

--- ansi_codepage()
-- ANSIコードページの値を返す.
-- @returns ANSIコードページの値(失敗=nil)
function ansi_codepage()
  local ok, ret = pcall(function()
    -- setlocale(LC_CTYPE, NULL) と同じ. 
    -- 現在のロケールの値の文字列を返す.
    local org = assert(os.setlocale(nil, "ctype"))
    -- Windowsにおいて, 既定のロケールを設定し, そのときに特に
    -- ANSIコードページを指定する. 戻り値は実際のロケールの値
    -- で, Windowsの場合 "言語_地域.コードページ" という形式の
    -- 文字列になる.
    -- Windows以外では ".ACP" というロケール名は無効であるため,
    -- nilを返し, assertがエラーを発する.
    local ret = assert(os.setlocale(".ACP", "ctype"))
    -- 一度変更したロケールを元に戻す.
    assert(os.setlocale(org, "ctype"))
    -- 先述の文字列の中のコードページの数字列を抽出し, 数値に変換
    -- したものを返す. 形式不正ならエラーになる.
    return assert(tonumber(ret:match("^.*%.(%d+)$")))
  end)
  -- 失敗ならnil, 成功ならret
  return (ok or nil) and ret
end

print(("ANSI cp = %s"):format(ansi_codepage()))

日本語版 Windows での実行結果は以下の通り。

ANSI cp = 932