2005年11月22日 火曜日

なんでもかんでもExcel症候群

何でもかんでもPowerPoint症候群の弊害を日記で書いたのだが、それよりも世の中に広く広まっている病的な物と言えば、_なんでもかんでもExcel症候群_であろう。とにかく通常の表だけに飽きたらず、提出書類から報告書まで_何でもかんでもExcel_なのである。つまり「何でもかんでもExcel症候群」とはExcelだけですべての仕事が完結してしまう恐ろしい病気なのだ。
その病巣の由来を簡単に予想するとすれば、子供の頃に升目の入ったノートで漢字の書き取りをやらされ(つまりカーニングとかに無頓着になる)、読書感想文などの類は原稿用紙で書かされ、漢字は少ない文字数で情報量を詰め込めることからすっきりとした表が書きやすく、何でもかんでも_表にしないと気が済まない_という日本人の悲しい習性に由来する物であろうと思うのだ。
まぁUnixでEmacsしか使わないというのと似たような話ではあるのだが、典型的なEmacsユーザーが扱うのは汎用的なテキストファイルであり、Emacs LISPでがんがんプログラムを書く(設定ですらLISPを書かねばならないので、多少は誰でも書く物だ)人が多い用に思われる。Excelの場合は、XLS形式という特殊なフォーマット(最近のはXMLなのか?)を用い、適当なワークシート関数などを表層的に使いこなしている人が多く、Excelの基本技とも言えるピボットテーブルとかソルバーを使いこなしている人がどの程度いるかと問えば、結構怪しい物だ。
まぁ会社で働いているとこういう病的な世界と常に隣り合わせであり、いつも精神汚染を受けているのであるが、これを前向きに楽しむにはどうすればいいか? ということに焦点を絞り込んで生活しないとやってられないと言うことになるであろうか。
そんなわけでExcelをちゃんと使いこなすにはVBAで遊びまくればいいのであるが、テキストファイルとのつきあいもやめられない。Unixな環境に一度でも触れてしまうと、VBAのお気軽さを楽しんでいても感じる最大の問題点は_正規表現が使えない_と言うところがなやましい。これまで正規表現(とハッシュ)を使うためにVBAからだと駄目だと思い、Active PerlとかActive Rubyとか非VBAでCOMオブジェクトをさわれる言語を選択していたのであるが、書いたプログラムを使ってもらうのに_わざわざPerlだのRubyだのをインストールしてもらわねばならない_という痛い問題があった。Windowsで全然閉じていないのである。Mac OSXみたいにPerlとかRubyがインストールされていればこんなことは考えなくて良いのだが、PerlやRubyを使うのは_Windows的なやり方ではないのである_と言う結論に落ち着いた。
Windows的にどうすればいいのかと言う話なのだが、結局のところ現在のほぼすべてのオフィスにあるWindows環境で前提として良さそうな物は、Internet Explorer 6 SP2とExcelであろうと言うことになる。いろいろ調べているとIE5以降だと、WIndows Scripting Hostが使える。_まてよWSHにはたしか正規表現オブジェクトがあったぞ_と思い出して、さらにCOMで呼び出せるじゃんと言うことを思い出したので、一気にこの方面の悩みが解消した。要はWSHの正規表現オブジェクトをVBAのオブジェクトにしてしまえばいいのである。なんてこったい。こんなので数年悩んでたよ。とりあえず、あるディレクトリにある複数のファイルを選択して、そのすべてのファイルに、入力したパターンマッチをして置換を行うVBAプログラムを書いてみよう。

Option Explicit
' RESample Programed by Kentaro OGAWA <kentaro@nn.iij4u.or.jp>
Public Sub RESample()
    
    ' 変数の宣言
    
    Dim RE As Object
    Dim Filenames As Variant
    Dim FileCount As Integer
    Dim OutputFile As String
    Dim StreamString As String
    Dim Pattern As String
    Dim ReplaceString As String
    
    '正規表現オブジェクトの準備
    Set RE = CreateObject("VBScript.RegExp")
    
    Pattern = InputBox("検索パターンを入力")
    ReplaceString = InputBox("置換文字列を入力")
    
    With RE
        .Pattern = Pattern
        .IgnoreCase = False
        .Global = True
    End With
    ' 処理ファイルの選択
    Filenames = Application.GetOpenFilename _
        (FileFilter:="すべてのファイル(*.*), *.*", _
        Title:="必要なファイルを選択して,「開く」ボタンを選択してください。「カンマ (,)」と「コロン (:)」で区切ります。", _
        MultiSelect:=True)
    If IsArray(Filenames) = False Then
    
        If Filenames = False Then
            MsgBox "「キャンセル」ボタンを選択しました"
        End If
    
    Else
    
        For FileCount = 1 To UBound(Filenames)
            
            OutputFile = Filenames(FileCount) + ".new"
            
            Open Filenames(FileCount) For Input As #1
            Open OutputFile For Output As #2
            
            Do While Not EOF(1)
            
                Line Input #1, StreamString
                Print #2, RE.Replace(StreamString, ReplaceString)
                
            Loop
            Close #1, #2
            
        Next FileCount
    
    End If
    Set RE = Nothing
End Sub

こんな感じでいいのかねえ。まぁ普通にExcel VBAをやっている人は結構見かけるのだけどちゃんとファイル入出力を書いている人は見たことがないのだが… Rubyとかでやれば数行のプログラムなのであるが、VBAでやるとかなり冗長だ。まぁPaul Grahamが言うところの_力のない_言語なのでその辺は見切りが必要。
まぁExcelを使っている人でファイル入出力で正規表現を使う人は似非である。典型的な「なんでもかんでもExcel症候群」の人の基本は、セルに読み込んで一個ずつ検索し、データの出し入れは2次元ポインタと見なして、_値の記憶とかの操作はCell関数をつかってセル単位で行い、ワークシート関数を使う_ってやるって言うものだ。僕はポインターがわからないのでExcel使いじゃありません。(上のソースも別にWordのマクロとしても動くのを忘れてはいかん。ついでにほぼそのままVB6でも動く。試してないが。ちなみにExcelVBAでみる変態的なポインタの使い方がわからんだけで、毎日C++でSTLは使い込んでますよ。)
この道はまだまだ深いので次回に続く。まったくちょっと調べただけで、VBAスキルが20くらいあがってしまったぞ…