すがブロ

sugamasaoのhatenablogだよ

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

修正版

エスケープシーケンスチェックあたりのロジックミスがあったので修正した版。
その他、ループ部分やエスケープシーケンス部分のチェックの記述方法を変更した。

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

  # 文字数カウント処理(バイトの配列にしてループさせる)
  str.to_s.unpack('C*').each_index do |index|
    # 改行コードは除外
    next if str[index] == 0x0a

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

    # エスケープシーケンスチェック
    if str[index] == 0x1b or esc_flag
      esc_flag = true
      esc_string << str[index]
      # 2バイト文字カウントフラグを off
      wide_byte_flag = false
    end

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