バイト数ではなく、文字数でもなく、文字が半角で幾つあるかの話。 コンソール・アプリケーションを作る上で問題になることが多いと思う。
で、PowerShell において、日本語や Emoji を出力してもカラムがある程度正しく表示されるので凄いなと思っていた。 (Emoji の一部は崩れたりして完全ではないけど)
PS1> [PSCustomObject]@{ カラム1 = "あいうえお"; col2 = "💩💩😀"; col3 = "value" }
カラム1 col2 col3
------- ---- ----
あいうえお 💩💩😀 value
PowerShell で文字幅を得る
どうやっているんだろう? と調べた結果、以下の方法で幅を得られると判明した。
PS1> $Host.UI.RawUI.LengthInBufferCells("💩")
2
PS1> $Host.UI.RawUI.LengthInBufferCells("あいうえお")
10
C# から
Cmdlet
実装クラスから使用可能
class Command : Cmdlet
{
void Method()
{
int cellWidth = CommandRuntime.Host?.UI.RawUI.LengthInBufferCells("aa")
?? throw new NullReferenceException();
}
}
コード
内部の具体的な実装は以下のコードと思われる。
internal static int LengthInBufferCells(char c) { // The following is based on http://www.cl.cam.ac.uk/~mgk25/c/wcwidth.c // which is derived from https://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt bool isWide = c >= 0x1100 && (c <= 0x115f || /* Hangul Jamo init. consonants */ c == 0x2329 || c == 0x232a || ((uint)(c - 0x2e80) <= (0xa4cf - 0x2e80) && c != 0x303f) || /* CJK ... Yi */ ((uint)(c - 0xac00) <= (0xd7a3 - 0xac00)) || /* Hangul Syllables */ ((uint)(c - 0xf900) <= (0xfaff - 0xf900)) || /* CJK Compatibility Ideographs */ ((uint)(c - 0xfe10) <= (0xfe19 - 0xfe10)) || /* Vertical forms */ ((uint)(c - 0xfe30) <= (0xfe6f - 0xfe30)) || /* CJK Compatibility Forms */ ((uint)(c - 0xff00) <= (0xff60 - 0xff00)) || /* Fullwidth Forms */ ((uint)(c - 0xffe0) <= (0xffe6 - 0xffe0))); // We can ignore these ranges because .Net strings use surrogate pairs // for this range and we do not handle surrogate pairs. // (c >= 0x20000 && c <= 0x2fffd) || // (c >= 0x30000 && c <= 0x3fffd) return 1 + (isWide ? 1 : 0); }