-K
と $KCODE
の違いはなんですか?ruby 1.6以降、デフォルトで漢字コードを特別に解釈しなくなりました。 漢字を扱いたい場合は ruby -Ke などとして$KCODE を適切に設定しておく必要があります。
Windows 上で SJIS を使用している場合、ruby -Ksを、 UNIX 系 OS 上で EUC を使用している場合、ruby -Keを UTF-8N を使用している場合、ruby -Kuを 指定する必要があります。
なお、スクリプトの先頭行に
#! ruby -Ks
などと書けばオプションの指定をスクリプトに埋め込むことができます。 これがもっとも無難でポピュラーな方法です。
-K
と $KCODE
の違いはなんですか?効果が及ぶタイミングが違います。
例えばSJISコードのファイルで以下のスクリプトがあった場合
$KCODE = 'SJIS' s = "表"
$KCODE に値を設定する段階ではスクリプトは解析された後です。文字列リテ ラルは($KCODE のデフォルトが "NONE" であるため)マルチバイトとして解釈 されていません。
オプション -K による漢字コードの指定ならばスクリプトを読む前に漢字コー ドが指定されるので、スクリプト解析の段階で漢字コードを認識します。
ちなみに漢字コードを含んだスクリプトで問題が発生する理由は「表」などの 文字がシフトJISコードでバックスラッシュ("\")と同じコードを含むからです。
-K オプションを正しく指定すれば、漢字で始まる変数名は英小文字に相当するもの として使えます。ポータビリティが低いのでおすすめできません。
Hash を使えば似たようなことができます、こちらの方がより安全と言えます。
var = {'変数' => '値'} var['変数'] = 1
$KCODE を設定した上で split(//) や scan(/./) を使います。
組み込みの String#tr は、バイトごとに変換します。
require "jcode"
とすると、日本語を文字ごとに扱えます。
(jcode.rb を参照)
以下は、ひらがなの濁音、半濁音、拗音、撥音の文字を無視してソートを行う例です。 *1
require "jcode" a = "ぁぃぅぇぉがぎぐげござじずぜぞだぢづでど" \ "ばびぶべぼぱぴぷぺぽゃゅょっゎ" b = "あいうえおかきくけこさしすせそたちつてと" \ "はひふへほはひふへほやゆよつわ" ary = %w(ふー ばー ばず) p ary.sort p ary.collect{|l| [l.tr(a,b), l]}.sort.collect!{|e| e[1]} # => ["ばー", "ばず", "ふー"] # ["ばー", "ばず", "ふー"]
余談ですが、version 1.7 以降なら Enumerable#sort_by を 使って最後の行を
p ary.sort_by {|l| l.tr(a,b)}
と書けます。
正規表現で[あ-ん]というような範囲表現が使えますが、機種依存文字を直接 書くことはプログラムの可読性を損ないます。かといって
gsub(/[\x84\xbf-\x88\x9f]/s, ' ')
と書くことはできません。このような場合は以下のトリックを使うことで
gsub(Regexp.compile("[\x84\xbf-\x88\x9f]", nil, 's'), ' ') または gsub(/#{"[\x84\xbf-\x88\x9f]"}/s, ' ')
2バイトコードの範囲をうまく数値で表現して、空白に置き換えることができ ます。(余談ですが、このようなときには空白でなくゲタ("〓")に置き換えま すけどね)
標準ならば nkf.so ライブラリを使う方法と jcode.rb ライブラ リを使って変換を行う方法があります。あと [RAA:Kakasi] ライブラリな どでも可能です。
[ruby-list:10505], [ruby-list:25839], [ruby-list:31238], [ruby-list:31240], [ruby-list:31508] などなど*2
Ruby はいわゆる半角カナを完全にはサポートしてません。
# 以下の例で "ア" は半角文字としてみてください ruby -Ks -e 'p "あア"' => "あ\261"
開発中の M17N版 ruby ではこのようなことにはならないそうです。
多バイト文字の切り出しでは、文字の泣き別れが問題になるのです が、これに対しては $KCODE を設定したとき /./ が、分断された 文字にマッチしないことを利用できます。
$KCODE = "e" p /./ =~ "あ"[0,1] # => nil # 注:漢字の要素になり得ない文字コードにはマッチします。 p /./ =~ "\xff" # => 0
以下は、文字列の左からたかだか len バイトまでを切り出すメソッ ド jleft のサンプルです。
class String def jleft(len) return "" if len <= 0 str = self[0,len] if /.\z/ !~ str str[-1,1] = '' end str end end $KCODE = 'e' s = "あいうえお" for i in -2 .. s.size+2 p [i, s.jleft(i)] end => [-2, ""] [-1, ""] [0, ""] [1, ""] [2, "あ"] [3, "あ"] [4, "あい"] [5, "あい"] [6, "あいう"] [7, "あいう"] [8, "あいうえ"] [9, "あいうえ"] [10, "あいうえお"] [11, "あいうえお"] [12, "あいうえお"]
もう一つ EUC コード限定で以下のような方法があります。
class String def jleft(len) return "" if len <= 0 str = self[0, len] if str.count("\xa1-\xfe") % 2 == 1 str[-1, 1] = '' end str end end
注:いずれも 3 バイト文字には対応してません。
NKF の -f
オプションが利用できます。
require 'nkf' p NKF.nkf("-ef11", "あいうえお、かきくけこ")
ただ、こちらは禁則処理やスペースの調整などを行ってくれて 賢すぎるので細かく制御できない場合があります。
自力でやるには 10.10 の方法を応用します。
class String def jfold(len) return "" if len <= 0 right = self.delete("\r\n") while right and not right.empty? left, right = right.unpack("a#{len} a*") if /.\z/ !~ left right[0,0] = left[-1,1] left[-1,1] = '' end yield left end end end "あいうえお、かきくけこ".jfold(11) {|s| puts s } # => あいうえお 、かきくけ こ
ただ、これは n バイト毎の folding です。TAB の桁位置を考慮し ていません。また、nkf に比べれば格段に遅いです。
10.1 漢字を含んだスクリプトが文字化けを出力したり、正しく実行できない場合があります の項目をチェックしたにもかかわらず、どうしても UTF-8 を正しく解釈してくれない場合は、 UTF-8 と UTF-8N の違いを疑ってみる必要があるかもしれません。
このリファレンスマニュアルでは単に UTF-8 と書かれていますが、 実は ruby インタープリタが解釈するのは UTF-8N です。一般的なエディタでは 暗黙的に UTF-8N のみを取り扱いますが、一部のエディタ*3では UTF-8 と UTF-8N を区別します。このような場合には UTF-8N で保存してみてください。
*1あらい 2001-10-07: 例が悪かった(^^;
*2適当に誰かまとめてちょうだい執筆者募集
*3 RDEで確認。