読者です 読者をやめる 読者になる 読者になる

Y-Ken Studio

新しもの好きのインフラエンジニアが四方山話をお届けします。

Rubyで全角英数字を半角英数字にnkfで変換する時の落とし穴

RubyUTF-8文字列の全角英数字の表記揺れを統一したいとき、 気をつけないと希に文字化けする事象を見つけたのでメモします。

f:id:yoshi-ken:20150605122403p:plain

NKFを用いて全角英数字→半角英数字に変換する方法

ググるとよく出てくる方法は次の通りです。
もちろん、問題なく普通に動きます。

$ pry
[1] pry(main)> require 'nkf'
=> true
[2] pry(main)> NKF.nkf('-m0Z1 -w', "Ruby−2.2")
=> "Ruby-2.2"

ここでWindows機種依存文字が混じるとどうなるでしょうか。

pry(main)> NKF.nkf('-m0Z1 -w', "ルビー Ⅱ")
=> "ルビー Ⅱ"
pry(main)> NKF.nkf('-m0Z1 -w', "ルⅡ")
=> "繝ォ竇。"
pry(main)> NKF.nkf('-m0Z1 -w', "Ruby Ⅱ")
=> "Ruby 竇。"

なんと、文字の組み合わせ次第では化けてしまいます。これは気づきにくいですね。
調べると、機種依存文字に関するオプションを発見しました。

--cp932 Windows機種依存文字(〜−¢£¬|など)をUnicodeに変換するときに文字化けしないようにする。
引用元: http://www003.upp.so-net.ne.jp/NAMBOKU/ruby/ruby0352.html

試しにこの引数を追加すると、期待通りの動作とは・・・なりません!!!
まあ元がUTF-8なのでcp932を指定するのも変だとはうすうす思っておりましたが。

pry(main)> NKF.nkf('-m0Z1 -w --cp932', "ルビー Ⅱ")
=> "ルビー Ⅱ"
pry(main)> NKF.nkf('-m0Z1 -w --cp932', "ルⅡ")
=> "繝ォ竇。"
pry(main)> NKF.nkf('-m0Z1 -w --cp932', "Ruby Ⅱ")
=> "Ruby 竇。"

ここで1度、引数のそれぞれの意味を見てみましょう。

引数 意味
-m0 MIME(電子メール用のフォーマット)に変換しない
(nkfはこのオプションを指定しない限り、MIMEに変換する処理を行う)。
-Z1 全角スペースを半角スペース1個に変換する。
-w 出力ファイルの文字コードUTF-8(BOMなし)とする(-W80とおなじ)。

引用元: http://www003.upp.so-net.ne.jp/NAMBOKU/ruby/ruby0352.html

ここで気づくのは、入力文字コードの指定が行われていないことです。
このため、先ほどのcp932のオプションはShift_JISでの読み込み時に使うものであったことが分かりました。
そこで、次のように-wと-Wをそれぞれ指定してみましょう。

引数 意味
-m0 MIME(電子メール用のフォーマット)に変換しない
(nkfはこのオプションを指定しない限り、MIMEに変換する処理を行う)。
-Z1 全角スペースを半角スペース1個に変換する。
-W 入力ファイルの文字コードUTF-8(BOMなし)とする(-W80とおなじ)。※追加※
-w 出力ファイルの文字コードUTF-8(BOMなし)とする(-W80とおなじ)。
pry(main)> NKF.nkf('-m0Z1 -W -w', "ルビー Ⅱ")
=> "ルビー Ⅱ"
pry(main)> NKF.nkf('-m0Z1 -W -w', "ルⅡ")
=> "ルⅡ"
pry(main)> NKF.nkf('-m0Z1 -W -w', "Ruby Ⅱ")
=> "Ruby Ⅱ"

無事に期待通りの動作となりました。

まとめ

rubynkfを利用するときは、入力文字コードを自動判定ではなくしっかりと指定しましょう!

引数 意味
-S 入力ファイルの文字コードshift_jisとする。
-E 入力ファイルの文字コードEUC-JPとする。
-J 入力ファイルの文字コードISO-2022-JP(いわゆるjisコード)とする。
-W 入力ファイルの文字コードUTF-8(BOMなし)とする(-W80とおなじ)。

あわせて読みたい

半角英数字に変換し、さらに機種依存文字も変換したいケースでは、
NKFではなく次のページで紹介されているunicode gemが万能でお勧めです。

文字列の表記揺れをUnicode正規化で簡単に解決する方法
http://qiita.com/y-ken/items/d08eb7f66c8fb2fa7d21

プログラマのための文字コード技術入門 (WEB+DB PRESS plus) (WEB+DB PRESS plusシリーズ)

プログラマのための文字コード技術入門 (WEB+DB PRESS plus) (WEB+DB PRESS plusシリーズ)

jqコマンドをsudoを使わずにインストールし、PATHを通す方法

JSONデータをコマンドラインでフィルター出来るjqコマンド、便利ですよね。 割と新しいepelリポジトリであれば、yum -y install jqで使えるようになります。 しかし次のようなケースでは大抵フルパスでバイナリを指定するのではないでしょうか。

  • root権限はないが、jqコマンドが使いたい
  • PATHの設定を変更する操作は避けたい

しかし今回紹介する方法を使うと、とても簡単にPATHが通る状態にできます。

続きを読む

データ可視化アプリの新星、PrometheusをCentOSにインストールする方法

SoundCloudが内製しているモニタリングシステム「Prometheus」がいま気になっております。
時系列データベースを用いた柔軟なクエリ言語を用い、ダッシュボードによる可視化やアラート機能もあるそうです。

f:id:yoshi-ken:20150205191805p:plain

とりあえず使ってみたので、紹介します。

続きを読む

elasticsearchのファイルディスクリプタを監視する

elasticsearchはLuceneをベースにしているため、細かい粒度でのファイルを多く生成します。
そのため "too many open files" エラーが発生して停止しないよう、安定稼働のためには日頃のリソース監視が必要です。
では、どのようにファイルディスクリプタの利用状況を確認すれば良いのでしょうか。調べてみました。

続きを読む