wcコマンドで1単語で2単語文計算される日本語
今回wcコマンドをrubyで実装するにあたって、wcコマンドの挙動を確認していたところ表題の現象にぶち当たりました。
どの文字が1単語で2つカウントされているのかを調べていたところ文章
という文字の後ろに文字が入力されると1単語とカウントされていることに気づきました。
では、なぜ文章が2つカウントされているのか?
原因
- wcは1バイトごとで読んでいる。
- 日本語はマルチバイト
章
などの漢字はマルチバイトの中に16進数unicodeのNBSPに値する数列が入っている。- そのため1バイトごとで読んでるwcコマンドはNBPSのせいでスペースが入っているとカウントして1語増える
フィヨルドブートキャンプの生徒さんの説明がめちゃくちゃわかりやすかったのでまるまる引用すると、
佐藤(@universato) さん
詳細を説明すると、不可解な挙動が起きる原因は、(オプションなしの)wcコマンドが、マルチバイトの日本語などへ対応しておらず、1バイト単位で見ているためです。
Rubyだとbytes
メソッドで文字列をバイト単位に分割して、その数値をto_s(16)
で16進数表記に変換することで、文字コードを見れます。p "章".bytes # => [231, 171, 160] p "章".bytes.map{ |b| b.to_s(16) } # => ["e7", "ab", "a0"]
章
の文字にはA0
が含まれており、これがwcの単語の区切りを示すうちの1つのNBSP(ノーブレークスペース)と判定されてしまうため、単語数が多くカウントされてしまいます。NBSP(ノーブレークスペース)の文字コードを調べれば、0xA0
やU+00A0
と書いてあるはずです。このようにNBSPが含まれる単語は、日本語の中にそれなりの頻度で入っているので、カウント数がおかしくなります。
とのことでした。
文字コード奥が深い!!!
・NBSP(ノーブレークスペース)のunicode番号
Unicode一覧 0000-0FFF - Wikipedia
・マルチバイトについて
マルチバイト文字(多バイト文字)とは - IT用語辞典 e-Words
・NBSPとは??
HTMLで空白を入れたい時に使う謎の文字  とは? | あ総研
NBSPの実際の使用を想像できていないので半分ぐらいしか理解できてませんが、、
今日もまた学び