Python でおみくじ CLI を書きながら East Asian Width に殴られた


ターミナルで罫線を引きたい。たとえばこういう感じ:

╔════════╗
║ おみくじ ║
╚════════╝

問題は、罫線文字 (║, ═ …) と日本語が混在したときに右端がズレることだ。

原因

unicodedata.east_asian_width() は文字を F / W / H / Na / N / A に分類する。 罫線は A (Ambiguous) ── つまり「環境次第で 1 にも 2 にもなる」。多くのターミナルでは半角扱いだが、それを前提にしないとレイアウトが破綻する。

解決

def visual_width(text: str) -> int:
    width = 0
    for ch in text:
        ea = unicodedata.east_asian_width(ch)
        width += 2 if ea in ("W", "F") else 1
    return width

Ambiguous を 1 として扱うのが一番安全だった。CJK 設定の terminal で見たら違う結果になるが、いまの想定ユーザーには十分。

「美しさは右端が揃うことで生まれる」と祖母が言っていた(言ってない)。