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

すがブロ

sugamasaoのhatenablogだよ

JISコードの文字数を調べる

Ruby プログラム

ついカッとなって

2008/08/22:修正版→JISコードの文字数を調べる(2) - @sugamasao.blog.title # => ”コードで世界を変えたい”
文字数を調べるプログラムを作ってしまった。
ちなみに、 SJIS ではなく、 JIS のコードである。
JISコードは1バイト文字や2バイト文字の開始時にエスケープシーケンスとして、制御コードが3バイトはいるので単純にバイトで区切るとたいへんな事になる。
なので、無理くり作ってみた。こ汚いソースだけど、ブラッシュアップの前に、とりあえず動くソースということで。
ちなみに、作成にあたり、ここのエスケープシーケンスの表を握りしめながらやった。
http://ash.jp/code/code.htm

ソース

def jis_couner(str)
  esc_flag = false
  esc_string = ""
  wide_byte_flag = false
  wide_first_byte_flag = false
  count = 0 # JIS での文字数カウント1

  # 文字数カウント処理
  str.each_byte do |s|
    # 改行コードは除外
    next if s == 0x0a

    # 2バイト文字フラグがあって、1バイト目を通過している場合
    if wide_byte_flag && wide_first_byte_flag && (s >= 0x21 && s <= 0x7E)
      count += 1
      wide_first_byte_flag = false
    elsif wide_byte_flag && (s >= 0x21 && s <= 0x7E)
      # 2バイト文字フラグがあって、1バイト目お通過いていない場合
      wide_first_byte_flag = true # 1byte 目通過フラグ on
    else 
      count += 1
    end

    # エスケープシーケンスチェック
    if s == 0x1b or esc_flag
      esc_flag = true
      esc_string << s
    end

    # エスケープシーケンスが3文字に達した時点で評価する
    if esc_string.size == 3
      # エスケープ文字列かチェックする
      # if:1バイト文字 elsif 2バイト文字
      if esc_string =~ /(\x1b\x28\x42)/ or
          esc_string =~ /(\x1b\x28\x4A)/ or
          esc_string =~ /(\x1b\x28\x49)/
        # 2バイト文字カウントフラグを off
        wide_byte_flag = false
        # 制御コード分の文字数をマイナスする
        count -= 3
      elsif esc_string =~ /(\x1b\x24\x40)/ or
          esc_string =~ /(\x1b\x24\x42)/ or
          esc_string =~ /(\x1b\x24\x44)/ 
        # 2バイト文字カウントフラグを on
        wide_byte_flag = true
        # 制御コード分の文字数をマイナスする
        count -= 3
      end
      # 初期化
      esc_string = ""
      esc_flag = false
    end
  end

  return count
end

# テストプログラム
file = []
File.open('./text.txt').each do |f|
  file <<  f
end


puts jis_couner(file.join('\n'))

ファイル内容

JISコードで以下のように書いてあるファイルをテストとして用意した

あいうえお12345
12345カキクケコ

実行結果

sugamasao% ruby ./char_count.rb
20

とりあえず、それっぽくカウントできているようだ。
っていうか、 JIS コードには制御コードがあって、それを使って1バイト文字と2バイト文字をチェックしているなんて、いままで知らなかったよ。。。