Zig言語でUTF-8の日本語を出力(Windows)
解決したいこと
Zig から派生した Zen 言語では Windows 上でも UTF-8 で書かれたソース(文字列)をなんの手を加えることもなく、コンソールに表示させることができますが、Zig for Windows では、コマンドプロンプトで予め「chcp 65001」としてUTF-8モードにしておかないと文字化けします。
以下のソースは、Zen言語で自動的に追加される「SetConsoleOutputCP」関数(Win32 API)を手動で追加したものです。mainの先頭で一回呼んでおけば、それ以降のコンソール出力がUTF-8を正常に受け付けるようになります。(chcp 932 の状態でも表示されます。また、chcp 932 の状態でも韓国語やアラビア語も表示できます)
const std = @import("std");
const windows = @import("std").os.windows;
const WINAPI = windows.WINAPI;
const BOOL = windows.BOOL;
const UINT = windows.UINT;
extern "kernel32" fn SetConsoleOutputCP(wCodePageID: UINT) callconv(WINAPI) BOOL;
pub fn main() anyerror!void {
_ = SetConsoleOutputCP(65001);
std.log.info("Zig の道へようこそ。\n道案内はこちらからどうぞ:\nhttps://ziglang.org/ja/\n", .{});
std.log.info("漢字(韓国語)=한자\n漢字(アラビア語)=كانجي\n", .{});
}
英語圏以外(でかつ Windowsのコンソールアプリ)なら必須の処理なので Zen 言語のように処理系が隠蔽してくれてもよさげに思いますが、「隠された処理」を嫌う Zig では取り込んでもらうのは無理かもしれません。
せめて、Linux や macOS とソースを同一化するために、「SetConsoleOutputCP」関数の宣言と呼び出しを Windows でない場合には削除したいのですが、どうすればよいのかわかりません。もしわかる人がいたら教えてください。
また、Zig for Windows で UTF-8 文字列を表示する他の良い方法があればそれでもかまいません。
よろしくお願いします。
このPRがそうなのでしょうか?有望そうに見えますが、英語が分からないので状況を正確に把握できません
https://github.com/ziglang/zig/pull/14411
このPRがそうなのでしょうか?有望そうに見えますが、英語が分からないので状況を正確に把握できません
https://github.com/ziglang/zig/pull/14411
少なくともすぐに取り込んでくれそうな雰囲気ではないですね。
C (実際には C++) との連携でクロスプラットフォームのソースができました:
https://github.com/blog-memo/zig-setconsoleoutputcp-2023-0909-1622
const std = @import("std");
const c = @cImport({
@cInclude("code.h");
});
pub fn main() void {
c.calling_c_from_zig();
std.log.info("Zig の道へようこそ。\n道案内はこちらからどうぞ:\nhttps://ziglang.org/ja/\n", .{});
std.log.info("漢字(韓国語)=한자\n漢字(アラビア語)=كانجي\n", .{});
}
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void calling_c_from_zig(void);
#ifdef __cplusplus
}
#endif
#include "code.h"
#ifdef _WIN32
#include <windows.h>
#endif
void
calling_c_from_zig(void)
{
#ifdef _WIN32
SetConsoleOutputCP(CP_UTF8);
#endif
}
build.zig
の中で使用するソースファイルを切り替えるようにしてみました。
0.11以降じゃないと動かないと思います。(最初、0.10で作っていたのに0.11で動かなかったので作り直しました‥)
やってることは @javacommons さんと同じようなことで、
- Windows → コードページ設定関数を呼ぶ
- それ以外 → 何もしない(ダミー関数を呼ぶ)
となっています。
@fuzzball さん・・・
2Factor Authentication が走るので、URL を張りなおさせていただきます:
https://github.com/fuzz6001/TestTargetSwitching/
いいですね、これ!C/C++のランタイムもいらないし、zig だけで書けて。
まさにこのソリューションが欲しかったんですよね。ありがとうございます。
#ifdef
とかがつかえない生 zig プロジェクトでは、(主に) Windows とそれ以外のプラットフォームとの間でのコード切り替えに役立つ大発見ですね!
exe.addModule("console", b.createModule(.{
.source_file = .{ .path = if (target.isWindows()) "src/console/windows.zig" else "src/console/default.zig" },
}));