トップ 最新 追記

2016-03-07 [長年日記]

_ Shift_JISの範囲外の文字を検出、見える化したい

まだちょっと悩んでるけど一応できたのでメモ。

若者のiconv離れ

とあるデータ加工作業があって、その中で Shift_JIS の範囲外の文字を置き換えていくという作業を行う必要があった。具体的には (株) とか「はしごだか」とかああいう文字ね。

で、これまでその辺はある程度お任せにしていて、必要になったら(実はここがミソ)自分が手で iconv をこんな風に

iconv -f sjis -t sjis filename > /dev/null

叩くことでダメな文字を指摘していた。iconv は nkf のようにいい具合に skip して処理しないので、Shift_JIS の範囲内で変換できない文字のところで以下のようにエラーを吐いて止まる。

iconv: filename:{line}:{col}: cannot convert

iconv なんてイマドキそんなに使わないのでは?と思いつつ古のワザをくり出していたのだけど、何せこの表示、見にくい。具体的には

普段テキストエディタで作業していない人には全然分かりやすくない

こんなことしなくても作業の練度が上がるとダメな文字が入ってくるパターンを学習して「だいたいこんな感じ」でいい具合に弾けるようになる。ところがこの学習の効いていない人に引き継ぐと、途端に難しくなってしまう。じゃあ iconv 使ってもらうかというとそれは厳しいなぁと思う次第。

Rubyで書けるのではと思ったら意外に難しかった

他にも加工を支援する必要があるのである程度のカタマリで rake task を用意していくことにした。*1そこで Ruby の Encoding でも不正な文字列が入っていると変換に失敗するので似たようなことはできるのではないかと思ってやり始めてみたら意外に奥が深かった。

結論から書くとこんな感じ。

  • 変換エラーで止まる際はどこの文字かヒントがない(バイト列は表示される)ので、 iconv よりも分かりにくい
  • Encoding#valid_encoding? は変換表に基づいて valid? の判断をしていないので、1文字ずつなめて valid でない文字の前もヒントととして表示してあげるといったことはできない
  • encode(enc, undef: :replace, replace: '??') みたいにするとダメな文字だけを特定しやすい文字に置き換えることはできる
    • ただし、全部同じ文字に置き換えられてしまうので、結局元のデータを修正する時は目視が必要
    • しかも問答無用で Windows-31J → Shift_JIS 変換を行ってはならない

全部ハマった。最後のものはどういうことかというと、

open(file, 'rb:Windows-31J').encode('Shift_JIS', undef: :replace, replace: '??')

で目的が達成できるかと思ったら、〜 がすべて不正な文字扱いになってしまう。

正しい Shift_JIS として記録されているのに Windows-31J として読み込んでしまうと 〜 を Shift_JIS の範囲外の文字として扱ってしまう*2。これを encode('Shift_JIS') してしまうと不正な文字だらけになってしまって意味がない。

結局こうなった

  begin
    open(f, "rb:Shift_JIS:UTF-8").read
  rescue Encoding::UndefinedConversionError => e
    fulltilde = "\x81\x60".force_encoding("Windows-31J")
    tmptab    = "\v".force_encoding("Windows-31J")

    s = open(f, "rb:Windows-31J").read.gsub(fulltilde, tmptab)

    diff = s.encode("Shift_JIS", undef: :replace, replace: "??".colorize(:magenta)).encode("Windows-31J").lines - s.lines

    if diff.size > 0
      puts ""
      puts f

      puts diff.map {|e| e.gsub(tmptab, fulltilde).encode("UTF-8")}
    end
  end

Shift_JIS から UTF-8 に変換できない時だけ Windows-31J として読み込んで、その後 Sift_JIS に変換を試みることで Shift_JIS に収まっていない文字を置き換える作戦。これでこの結果の画面は

  • ダメな文字を含む行だけが表示され、かつ
  • ダメだった文字はハイライトされている

ので、詳しくない人にも結構分かりやすい表示になるんじゃないか。

また、そのままだと 〜 が Windows-31J から UTF-8 へ変換される過程で Shift_JIS では扱えない文字となってしまい、軒並み undef になってチェックの意味を成さなくなるので、これは強制的に垂直タブに置き換えて問題なく動作するようにしている。

cf. String#encodeが変換できそうで変換できない文字 - ネットの海の片隅で

Tags: Ruby

*1 コマンドラインから作業するハードルがあるのは認める

*2 途中で UTF-8 に変換する際に対応関係が壊れるのか?


2016-03-24 [長年日記]

_ 最速ホムペ(PHP)案件staging環境 with Heroku

前提や対象者

  • Heroku が何か知っていてアカウントを持っていて Heroku Toolbelt インストール済みであること
  • Apache, Nginx, Git, PHP, Composer について普通の知識を持っていること

Heroku には Dropbox 連携の機能もあるけど、後述の応用を考えると間違いなく Git 使えて まともなコミットを作る力 をつけた方がよいです。

別に Heroku じゃなくて Bluemix でもなんでもよいです。単に自分の現在の環境ですぐ実現できるものが Heroku だっただけです。

やること

  • Git の準備
  • local の開発環境の準備
  • Heroku の準備

git の準備

$ git init

local の準備

composer.json
{
  "require-dev": {
    "heroku/heroku-buildpack-php": "*"
  }
}

以下のコマンドを叩いてもよい

$ composer require --dev heroku/heroku-buildpack-php
Procfile
web: vendor/bin/heroku-php-nginx

Apache より Nginx の方がよいです。サクッと立ち上げてサクッと確認。built-in サーバみたいな感じで使えるし速い。hhvm は試してないので知りません。

確認

$ heroku local

heroku の準備

  • アプリの追加
  • (buildpackの指定)
  • heroku git:remote -a

deploy

$ git push heroku <branch:>master

deploy して動かすだけなら composer.json は空でもよいし、Heroku のドキュメントはそうなっているが、どうせ Procfile が正しく動くかどうかは確認した方がよいので、require-dev に入れておくのがオススメ。

これに慣れておくとホムペレベルじゃなくてもう少し凝った仕組みに取り組む時もだいぶやりやすい。

応用編

production が FTP でしか繋がりません
lftp と rake とか使って自動化してください。-X を上手に設定しないといろいろ漏れるので気をつけるよろし。秘密情報は dotenv 使え。
そこそこ時間が掛かったり複数人で扱う案件、あるいは継続メンテする案件です
Bitbucket -> Codeship -> Heroku とか GitHub -> CircleCI -> Heroku の連携を設定しましょう。

いちいちリンク用意しないけど Heroku, Composer, Packagist など公式ドキュメントは読みましょう。

Tags: PaaS PHP