Contents
    1. まえがき
    2. 対策
    3. 修正後のスクリプト
    4. 注意
    5. さらに注意!

invalid byte sequence in UTF-8 (ArgumentError)

まえがき

諸事情により Mew のMH形式のメールボックスを mbox 形式に変換する必要があった

で mhdir2mbox.rb というスクリプトを作ってくださっているのでありがたく利用する。

ここにある、拡張子 .mew 対策も加えた。 ところが、入力テキストにUTF-8範囲外の変態なデータがあると

invalid byte sequence in UTF-8 (ArgumentError)

と言われて処理が停止してしまう。

対策

で紹介されている、

ic = Iconv.new('UTF-8//IGNORE', 'UTF-8')
valid_string = ic.iconv(untrusted_string)

というテクニックを使う。

修正後のスクリプト

以下のようになった(がこれだけでは完全に解決できなかった。後述)

#! /usr/bin/ruby
# Copyright (C) 2008 F.Narisawa <http://fn23.seesaa.net>
# Distributed under GPL
# Version 0.1.2
require "find"
require "fileutils"
require "iconv"

CRLF = "\r\n"

def mkdirp(dnm)
  if File.directory?(dnm) then
    return
  else
    parentdir = dnm.gsub(%r{/[^/]*$},"")
    print "parentdir = #{parentdir}\n"
    if parentdir !~ %r{^[/.]+$} && parentdir.length > 0 then
      mkdirp(parentdir)
    end
    print "Make Directory: #{dnm}\n"
    Dir.mkdir(dnm)
    fn = dnm.sub(%r{.sbd$},'')
    print "Make Emptyfile: #{fn}\n"
    open(fn,"w").close
  end
end  


curdir = Dir.pwd
if ARGV.length < 1 then
  $stderr.print "mhdir2mbox.rb -d <tgtdir> <srcdir 1> [<sredir 2>...]"
  exit;
end

if ARGV[0] == "-d" then
  ARGV.shift
  tgtdir = ARGV.shift
else
  tgtdir = curdir
end
if ! File.directory?(tgtdir) then
  $stderr.print "ERROR: Could not find directory: #{tgtdir}.\n"
  exit -1
end

ARGV.each do |srcdir|


  if ! File.directory?(srcdir) then
    p "Can not find #{srcdir}."
    next
  end
  #srcdir = "./inbox"
  #  tgtname = tgtdir + "/" + srcdir.gsub('/', '_').gsub('.','_')  + ".mbox"
  srcname = srcdir.sub(%r{^\./}, "")
  srcname = srcname.sub(%r{/$}, "")
  if srcname =~ %r{\.+$} then
    p "Can not get directory name "#{srcname}". Skip."
    next
  end
  tgtname = tgtdir.sub(%r{/$},"") + "/" + srcname.gsub('/', '.sbd/')
  $stderr.print "Source = #{srcname}\n"
  $stderr.print "Target = #{tgtname}\n"
  $stderr.flush
  
# ディレクトリ作成
  dirnm  = File::dirname(tgtname)
  if ! File.directory?(dirnm) then
    mkdirp(dirnm)
  end

# ファイル作成
  tgtfil = open(tgtname, "w")
  
#  Find.find(srcdir){|fpath|
# 取り込み元ディレクトリからファイル読み出し
  Dir::foreach(srcdir)do |f|
    fpath = srcdir + "/" + f
    # if File.file?(fpath) and fpath =~ %r{/[0-9]+$} then
    if File.file?(fpath) and fpath =~ %r{/[0-9]+(\.mew)?$} then
      fromfil = open(fpath)
      tgtfil.print CRLF,"From - ",CRLF # 区切挿入
      while text = fromfil.gets do
        text.chomp!
        # text.encode('UTF-8') # added
        ic = Iconv.new('UTF-8//IGNORE', 'UTF-8')
        valid_text = ic.iconv(text + ' ')[0..-2]
        valid_text.sub!(/\A(>*)From /,'\1>From ')
        tgtfil.print valid_text,CRLF
      end
      $stderr.print "."
      $stderr.flush
    end
  end
  tgtfil.print CRLF
  print "\n"
end

注意

Iconvは will be deprecated で、

in `require': iconv will be deprecated in the future, use String#encode instead.

と言われる

さらに注意!

これでも対処できない無効文字があって、

in `iconv': "\xE0 " (Iconv::InvalidCharacter)

と言われた。String#encode を使えば解決できるんかなあ。

Last modified: 2013-10-22 Attached files total: 6MB