D言語で半角・全角含めた文字幅を取得するeast_asian_width


はじめに

昨年のアドベントカレンダーで、d-man{say,think}を開発しました。
ところが全角文字に対応していませんでした。

$ d-mansay D言語くんだよ
 _____________________
< D言語くんだよ             >
 ---------------------
    \    _   _
     \  (_) (_)
       /______ \
       \ (O(O \/
        | | | |
        | |_| |
       /______/
         <   >
        (_) (_)

そこで今回は全角文字に対応させます。

east_asian_width

文字通りのdubパッケージがあります。
https://code.dlang.org/packages/east_asian_width
READMEから使い方を抜粋します。

import eastasianwidth;

assert(displayWidth("あいうえお") == 10);

// '☆' is Ambiguous character
assert(displayWidth('☆') == 1);
assert(displayWidth('☆', AmbiguousCharWidth.wide) == 2);
assert(displayWidth("☆D言語くん☆") == 11);
assert(displayWidth("☆D言語くん☆", AmbiguousCharWidth.wide) == 13);

assert(eastAsianWidth('A') == EastAsianWidthProperty.F); // Fullwidth
assert(eastAsianWidth('ア') == EastAsianWidthProperty.H);  // Halfwidth
assert(eastAsianWidth('ア') == EastAsianWidthProperty.W); // Wide
assert(eastAsianWidth('A') == EastAsianWidthProperty.Na); // Narrow
assert(eastAsianWidth('☆') == EastAsianWidthProperty.A); // Ambiguous
assert(eastAsianWidth('À') == EastAsianWidthProperty.N);  // Neutral

displayWidth('☆', AmbiguousCharWidth.wide) を使ってあげれば良さそうです。

Improve d-man{say,think}

というわけで実装しました。

$ d-mansay 新しいD言語くんは日本語が流暢だよ -W 17
 ___________________
/ 新しいD言語くんは \
\ 日本語が流暢だよ  /
 -------------------
    \    _   _
     \  (_) (_)
       /______ \
       \\(O(O \/
        | | | |
        | |_| |
       /______/
         <   >
        (_) (_)

参考