2011/12/16


こういう作業ってプログラマなら日常茶飯事で、やり方しらない新人プログラマはいつまでたっても新人なのだけど...
めんどうな作業がわずか数秒に!新人デザイナーが 知らないと一生後悔するExcelを使ったHTML生成 | Webロケッツマガジン

お客さんから送られてきた、Excelデータからせっせとリストや表のHTMLをコーディングしているあなた!そろそろ手がが疲れてきていませんか?

そんなあなたは、この記事で紹介するExcelテクニックをぜひ覚えてください。

面倒な作業が、わずか数秒で終わります!

http://webrocketsmagazine.com/entry/20111209/html-code-generation-using-excel.html
僕もこの記事見て最初は「これはVimmerに対する釣りだ。我慢しよう。」と思ったけど、寝れなかったので書いてみた。ちなみに数秒では終わりません。きっとExcelでも数秒では終わりません。

ただExcelよりは遥かに応用が効くし、どんなデータが来ってどんな出力形式を求められたって簡単に作れてしまう新人プログラマは、きっと誰の目にも輝く期待の星に見える事でしょう。

geek info
今回はこの表をHTMLにする。 ExcelやOpenOfficeからコピペすると、タブ文字がセパレータになった状態になっている。
ギーク名    得意技
miyagawa    それプラ
tokuhirom   patches welcome
xaicron lang:mattn
hasegawayosuke  xss
cho45   gerry++
まずこのタブ文字を区切り文字としてTDタグの終わりと、次のTDタグの開始を埋める。Vimの置換ではタブ文字は \t と表現する。
:%s!\t!</td><td>!g
とタイプする。これは簡単。すると
ギーク名</td><td>得意技
miyagawa</td><td>それプラ
tokuhirom</td><td>patches welcome
xaicron</td><td>lang:mattn
hasegawayosuke</td><td>xss
cho45</td><td>gerry++
こうなる。ちなみにVimの s コマンドはsの次の1文字が任意の置換セパレータになるのでかぶらない文字を使うと良い。
次に先頭にTRおよびTDの開始タグ、行末にそれらの閉じタグを入れよう。ついでにインデントもしよう。
:%s!.*!<tr>\r\t<td>&</td>\r</tr>!g
正規表現 .*で行全体を表して置換対象とする。& はその置換対象文字列に相当するので両側にそれぞれのタグおよび改行とタブ文字を入れた。
注意1: &を置換文字列にするには\&とする。エスケープしなくても良い方法もある。
注意2: Vimの置換では改行コードは CTRL-V CTRL-M で挿入される ^M を使っても良いが、\r でも同じ結果が得られる。
正規表現が使える他のエディタで & を置換対象文字列として扱えない場合は置換対象を (.*) にして置換文字列を <tr>\r\t<td>\1</td>\r</tr> とすればよい。さて上記のコマンドを実行すると <tr>
    <td>ギーク名</td><td>得意技</td>
</tr>
<tr>
    <td>miyagawa</td><td>それプラ</td>
</tr>
<tr>
    <td>tokuhirom</td><td>patches welcome</td>
</tr>
<tr>
    <td>xaicron</td><td>lang:mattn</td>
</tr>
<tr>
    <td>hasegawayosuke</td><td>xss</td>
</tr>
<tr>
    <td>cho45</td><td>gerry++</td>
</tr>
こうなる。中にはTDは縦並びがお好みの人もいるだろう。そんな人には
:%s![^\t]\zs\ze<td!\r\t!g
こうタイプしよう。ここで \zs\ze が何を意味するかについては tyru さんが書いた記事を見ると良い。
Vimのニッチな正規表現で遊ぼう - Humanity

Vimのニッチな正規表現で遊ぼう Vim さあみなさん Vim Advent Calendar も14日目ということで佳境にさしかかってきましたね! とか他のAdvent Calendarに参加してた...

http://d.hatena.ne.jp/tyru/20111214/play_with_vim_regexp
この行が意味するのは、タブ文字じゃない文字と、<td の間にある(実際は0文字)文字を\r\t
、つまり改行とタブ文字に置き換える事である。
同様にVimの方言が使えない他のエディタでやる場合は >< を置換対象文字列として置換文字列を >\r\t< にすると良い。
さて上のコマンドを実行するとこうなる。
<tr>
    <td>ギーク名</td>
    <td>得意技</td>
</tr>
<tr>
    <td>miyagawa</td>
    <td>それプラ</td>
</tr>
<tr>
    <td>tokuhirom</td>
    <td>patches welcome</td>
</tr>
<tr>
    <td>xaicron</td>
    <td>lang:mattn</td>
</tr>
<tr>
    <td>hasegawayosuke</td>
    <td>xss</td>
</tr>
<tr>
    <td>cho45</td>
    <td>gerry++</td>
</tr>
もう出来たも同然。先頭のTR内はTDじゃなくてTHだよって人はそこだけビジュアル選択して :'<,'>s/td/th/g
としとけば良い。さぁ仕上げよう。
ここは zencoding-vim を使う。
mattn/zencoding-vim - GitHub

zen-coding for vim: http://code.google.com/p/zen-coding/

https://github.com/mattn/zencoding-vim
以下の手順は最新版で無いと正しく動作しません

この状態で全ての行をビジュアル選択して
<C-y>,
をタイプする(CTRLキーとYを押したあとカンマ)。すると Tag:
と表示されるので、そこに
Tag: html:5>table[border=1]
と入力すれば <!DOCTYPE HTML>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title></title>
</head>
<body>
  <table border="1">
  <tr>
    <th>ギーク名</th>
    <th>得意技</th>
  </tr>
  <tr>
    <td>miyagawa</td>
    <td>それプラ</td>
  </tr>
  <tr>
    <td>tokuhirom</td>
    <td>patches welcome</td>
  </tr>
  <tr>
    <td>xaicron</td>
    <td>lang:mattn</td>
  </tr>
  <tr>
    <td>hasegawayosuke</td>
    <td>xss</td>
  </tr>
  <tr>
    <td>cho45</td>
    <td>gerry++</td>
  </tr>
  </table>
  
</body>
</html>
できあがり。簡単ですね。
手順はもっと短くできるし、それ専用のスクリプトを書けばいくらでも簡単にはなる。僕が言いたいのは、どんな入力データに対しても、求められる出力形式への置換方法さえしっていれば誰でもこういう編集が出来るということ。その為の道具としてvi/vimはおそらく無二のツールだと信じている。
Posted at by



2011/12/15


こうですか?わかりません
@hasegawayosuke

ExecuteExcel4Macro で CALL ワークシート関数使ってShellExecute呼んでそれでVimScript操作してHTMLを数秒で生成する Excel の使い方をたぶん mattn が書いてくれる。


http://twitter.com/hasegawayosuke/statuses/147123761429217280

まずGo言語のソース(動作には go-oleが必要) package main

import (
    "fmt"
    "github.com/mattn/go-ole"
    "github.com/mattn/go-ole/oleutil"
    "io/ioutil"
    "os"
    "path/filepath"
    "strconv"
)

func main() {
    ole.CoInitialize(0)

    unknown, _ := oleutil.CreateObject("Excel.Application")
    excel, _ := unknown.QueryInterface(ole.IID_IDispatch)
    defer func() {
        if excel != nil {
            oleutil.CallMethod(excel, "Quit")
            excel.Release()
        }
    }()

    path, _ := filepath.Abs(os.Args[1])
    sheet := os.Args[2]
    r1, _ := strconv.Atoi(os.Args[3])
    c1, _ := strconv.Atoi(os.Args[4])
    r2, _ := strconv.Atoi(os.Args[5])
    c2, _ := strconv.Atoi(os.Args[6])

    dir, file := filepath.Split(path)

    path = fmt.Sprintf(`'%s[%s]%s'`, dir, file, sheet)

    cwd, _ := os.Getwd()
    tmp, _ := ioutil.TempFile(cwd, "hasegawayosuke")
    defer os.Remove(tmp.Name())

    for r := r1; r <= r2; r++ {
        for c := c1; c <= c2; c++ {
            ret := oleutil.MustCallMethod(
                excel,
                "ExecuteExcel4Macro",
                fmt.Sprintf(`""&` + path + `!R%dC%d`, r, c))
            if c != c1 {
                fmt.Fprint(tmp, ",")
            }
            fmt.Fprint(tmp, ret.ToString())
        }
        fmt.Fprintln(tmp)
    }

    oleutil.MustCallMethod(
        excel,
        "ExecuteExcel4Macro",
        `CALL("shell32", "ShellExecuteA", "JJJCCJJ", 0, 0, "gvim", ` +
            `"""` + tmp.Name() + `"" -S session.vim", 0, 1)`)
}
そしてセッション用のvimscript %s!,!</td><td>!g|:%s!.*!<tr>\r\t<td>&</td>\r</tr>!g|:%s!><!>\r\t<!g
exe "normal! ggO<table>\<esc>Go</table>"
set ft=html
コマンドラインから excel4macro subtech.xls Sheet1 3 2 7 3  
こう実行する。引数はファイル名、シート名、開始行番号、開始列番号、終了行番号、終了列番号になります。
これで実行すると...

excel4macro
便利!ぇ
Posted at by



2011/12/14


追記
以下のリンクで○が付いている方の記事で電子書庫化をお願いしました。
筆者の皆さん、ご協力頂きありがとうございました。まだVim Advent Calendarは続きますので宜しくお願い致します。

Vim Advent Calendar 2011に寄稿もしくはこれから執筆される方に質問があります。
先日、技術評論社さんから電子出版についての提案がありましたが、Vimユーザをもっと増やしたいという個人的な意見もあり、出来れば全記事を電子出版化して欲しいと思っています。
16日が期限という事もありますが、希望されない方を優先したいと思っております。
もし、全員電子出版化に賛成という事であれば、私の方から技術評論社の方へのお願いは行います。twitterの@mattn_jp に返答頂くか、以下のコメント欄に回答お願い致します。

以上、宜しくお願い致します。
Posted at by