LoginSignup
3
3

More than 5 years have passed since last update.

UTF-8文字列を指定バイトに収まるように短くする

Posted at

ある理由により、UTF-8 な文字列を指定バイトに収まる最大長でぶったぎりたくなりました。
平たく言うと、Linux などで採用されているファイルシステムではファイル名の最大長が255バイトなので、Windows や Mac で作成されたファイルを保存できないことがあるのでなんとかしたいと思った訳です。
UTF-8は一文字あたりのバイト数が一定ではない文字コードなので、単に文字数でぶった切ると255バイトをオーバーしかねません。最大6バイトなので 255÷6で42文字にしておけば安全ですが、どうせならできるだけ長いファイル名にしたいってもんです。

Ruby/Rails 初心者の私は当然ながらそういうバイトぶった切りお手軽関数が用意されていることを期待したんですが、社内の達人に聞いたところ「ない」というにべもない答えが返ってきました。
ほんとかなと思って手を尽くして検索してみましたが、確かにないみたい・・・。
コピペプログラマとしては万事休すです。
しかしどう検索してもみつからないので、仕方なく自作しました。
あ、社内の達人もほんのちょっとだけ手伝っています。

      original_file_extension = File.extname(@original_filename)
      #@original_filename = File.basename(@original_filename)

      @original_filename.force_encoding("ascii-8bit")

      pp "ascii"
      pp @original_filename

      @original_filename = @original_filename[0, (configatron.uploadfilename.bytesize - original_file_extension.bytesize)]

      pp "slice"
      pp @original_filename

      @original_filename.encode!("UTF-16BE", "UTF-8", :invalid => :replace, :undef => :replace, :replace => '')
      @original_filename.encode!("UTF-8")

      pp "utf-8"
      pp @original_filename

      @original_filename += original_file_extension

      pp "bytesize"
      pp @original_filename.bytesize

configatron.uploadfilename.bytesize は255を設定しています。
ところどころデバッグライトしてますが、当然なくても動きます。
@original_filename はパスを含まないファイル名のみが渡ってくるの前提です。

+文字エンコーディングをASCII-8bitに変更してバイト単位のぶった切り
+String#encode を使用して、ぶった切りの際に発生した不正な UTF-8 文字列を更正

ってあたりが肝でしょうか。
後者については下記サイトを参考にしました。

Rubyでinvalidなバイト列を含むUTF-8文字列を扱う
Ruby の invalid byte sequence in UTF-8 例外を encode("UTF-8", "UTF-8") で回避するのはおかしいよ、という話

2バイト〜4バイトの UTF-8 文字列が混在するようなファイル名をいろいろ付けてみてテストしましたが、うまく動いてくれているようです。
最終行でぶった切り後のバイト数を表示していますが、253あたりの数字が表示されると、無駄なく使えている感が感じられて思わずにんまりしてしまいました。

「ここはこう直した方がいいんじゃない?」「その目的のコードはここに書いてあるよ!」と言った情報をお持ちの方は、ぜひ教えてくださいね。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3