2008-05-25 Excel VBAでブログに投稿する
XML-RPCを使うとExcelやAccessからブログに記事を投稿したり,修正したりすることができます。手順をご説明します。
概要
- metaWeblog.newPostのサンプル
- ブログの操作にはXML-RPC(vbXMLRPC.dll)を使う
- Excel,Accessに対応。おそらくWordでも可
注意事項
現在のvbXMLRPC.dll(Ver.0.9.0042)は,DBCS(Double Byte Character Set)に対応していないようです。どういう意味なのかというと,日本語を含む文字列を送受信させるとエラーになります。
「それじゃだめじゃん」ということになるのですが,裏技があるのです。日本語をすべて数値文字参照(&#xxxx;という形式)に置き換えてしまえば,日本語を通すことができます。
投稿された文章は,普通のWWWブラウザであれば問題なく表示されるのですが,携帯電話では文字化けするかもしれません。また,投稿される文章の中身は「&#xxxx;」という記号の羅列です。ブログの管理画面で再編集しようとしたときに,はっきり言って読めませんので途方に暮れることになるかと思います。
これらを考慮した上で以下を読み進めてください。
準備
(1) vbXMLRPC.dllのインストール
「vbXMLRPC Binaries Download」からダウンロードのページに進んで,vbXMLRPCのバイナリをダウンロードします(発電所の画像が出てくるかもしれませんが,気にしないでください)。ZIPファイルを「c:\program files\」以下に解凍しておきましょう。
(2) 参照設定
vbXMLRPCをVBAで使うための設定です。
(i) Excelを起動し「Visual Basic Editor」を起動します。
(ii) <Excel 2007を使っていてVisual Basic Editorの起動方法が分からない場合>Excel 2007ではリボンの「開発」タブから起動することができます。「開発」タブはExcelの標準設定では表示されません。Excelのオプションを開き,「[開発]タブをリボンに表示する」をチェックしておきます。<画像↓>
(iii) Visual Basic Editorの「ツール(T)→参照設定(R)」にて,参照設定ダイアログを開きます。「参照(B)」ボタンをクリックし,vbXMLRPC.dllを選択します。
(iv) 「vbXML - Simple XML Parser」と「vbXMLRPC - XML-RPC Client」の2項目をチェックし,OKをクリックします。<画像↓>
(3) ブログの設定
以下の4点を調べておきましょう。
- APIのエンドポイント(サービスのURI)
- ブログID
- ユーザ名
- パスワード
確認の仕方はお使いのブログによって異なります。また(当然のことですが)XMLRPCに対応していないブログでは使えません。
コード
以下,metaWeblog.newPostのサンプルコードです。実行すると少し待たされます。投稿時にブログが再構築されるからだと思います。ブログの設定を変えれば挙動が変わるのかもしれません。
Public Sub newPost() Dim linsRequest As New XMLRPCRequest Dim linsResponse As XMLRPCResponse Dim linsUtility As New XMLRPCUtility Dim linsStruct As New XMLRPCStruct linsRequest.HostName = "blog.sakura.ne.jp" ' ホスト名 linsRequest.HostPort = 80 ' ポート番号 linsRequest.HostURI = "/rpc/" ' パス linsRequest.MethodName = "metaWeblog.newPost" linsRequest.params.AddString "12345678" ' ブログID linsRequest.params.AddString "example.sakura.ne.jp" ' ユーザ名 linsRequest.params.AddString "password" ' パスワード ' linsStruct.AddString "title", HTMLEntity_encode("タイトル") linsStruct.AddString "description", HTMLEntity_encode("本文") linsStruct.AddString "dateCreated", "2007-04-01T00:00:00" linsRequest.params.AddStruct linsStruct ' content linsRequest.params.AddBoolean True ' publish Set linsResponse = linsRequest.Submit If linsResponse.STATUS = XMLRPC_PARAMSRETURNED Then ' リクエストが成功すると記事IDが返ってくる Debug.Print "id=" & linsResponse.params(1).StringValue Else Select Case linsResponse.STATUS Case XMLRPC_PARAMSRETURNED Debug.Print "Unexpected response from XML-RPC request " & linsResponse.STATUS Case XMLRPC_FAULTRETURNED Debug.Print "Server returned a fault. Code is '" & linsResponse.Fault.FaultCode & "', description is '" & linsResponse.Fault.FaultString & "'." Case XMLRPC_HTTPERROR Debug.Print "HTTP error encountered. Code is '" & linsResponse.HTTPStatusCode & "', description is '"& linsUtility.GetHTTPError(linsResponse.HTTPStatusCode) & "'." Case XMLRPC_XMLPARSERERROR Debug.Print "XML Parsing Error encountered '" & linsResponse.XMLParseError & "'." Case XMLRPC_NOTINITIALISED Debug.Print "Weird, the response claims not to be initialised !!!" Case Else Debug.Print "Double Weird, unknown response status '" & linsResponse.STATUS & "'." End Select End If End Sub Public Function HTMLEntity_encode(str As String) As String Dim ret As String ret = "" Dim i As Long Dim c As String Dim charCode As Integer Dim hexCode As String For i = 1 To Len(str) c = Mid(str, i, 1) charCode = AscW(c) If charCode > 127 Then hexCode = Hex(charCode) ret = ret & "&#x" & hexCode & ";" Else ret = ret & c End If Next HTMLEntity_encode = ret End Function
メモ
- vbXMLRPCを使わない方法 ― いまのところ代替手段を発見していません。Microsoftが正規に配布しているCOMで簡単にできそうなのですが,どうも見当たらないのです。XMLRPCはすでにレガシーな規格だそうで,この先,進展があるのかどうかも不透明です
- Word 2007のブログ機能 ― Word2007にはブログの管理機能が備わっていますが,これをVBAで操作するのは不可能なようです
いずれにしても何か分かったことがあったら,お知らせします。
ExcelとAccessどちらが良いのか
ExcelとAccessのどちらを使えばよいのか悩む人がいるかもしれません。なぜなら,今回のお題はExcelとAccessのどちらからでもできるのです。
Accessではデータに項目(フィールド)とデータ型を指定できますので,データ構造が堅牢になります。操作の不手際で,変なデータになってしまう危険性を低くすることができます。また項目には名前をつけることができるので,VBAの入力補完機能を利用して項目名を入力できるという利点もあります。「できる」ことがたくさんあるというわけですね。
対してExcelですが,仕事を早く片付けたい場合や職場で複数の人と作業している場合には魅力的な選択肢でしょう。「最適」とは言えないものの, Office付きのPCであれば必ずインストールされていますので入手しやすいです。また書籍やネットで入手できる情報量は,Excelの方が多いようです。
Excelであれば「困ったとき」に,だれかが助けてくれる可能性が高いと考えられるのです。
2007-11-03 Excel VBAで実体参照のエンコードとデコード
Excel VBAでHTMLの実体参照をエンコード・デコードするコードを作りました。コードそのものはVB6.0処理系汎用であり,Excel VBA以外でも使えると思います。
あらまし
「HTMLの実体参照」とは,HTMLのメタ文字をエスケープするための記述方法です。メタ文字とは,「タグ」を書くときに使う文字です(正確にはちょっと違うけど)。たとえば「<>」を書きたいときは,「< > 」と書かなければいけません。「<>」はHTMLのメタ文字なので,これらを直接,書いてしまうと「タグ」と区別がつかなくなってしまうのです。
Excelで実体参照の混ざった文字列を扱うことは,あまりないと思いますが,あまりないがために必要に迫られたとき困るのです。
動作概要
- 実体参照を解決するクラスモジュール(HTMLEntity)を作る
- 「実体参照」と「文字」の対応表を作ることで,双方を変換できるようにする
- 実体参照のパターン抽出には正規表現(Scripting.Regexオブジェクト)を使う
仕様
- エンコード対象の文字は「&<>"」のみ
- デコードは文字実体参照と数値文字参照(10進と16進)に対応
- 誤記により実体参照の末尾の「;(セミコロン)」が存在しなかった場合も,なるべくデコードする
- 対応する文字実体参照は「ISO 8859-1」「一般記号,数学記号,ギリシア文字」「マーク付け記号,国際化文字」だが,デコードした結果のすべての文字コードをExcelで表示できるとは限らない
注意事項
- このコードは無保証です
- 細かな挙動は不明です。たとえば「巨大な文字列に適用した場合」「マッチ数が極端に多い場合」にどんな挙動をするのか明らかではありません。またエンコード・デコードの正当性(本当に正しいのかどうか)は十分に検証しておりません
- このコードはオブジェクト初期化時の計算コストが高いです。一度,生成したオブジェクトはなるべく使い回すようにしてください。とくにループの内部で何度もオブジェクトを生成してはいけません。スループット(処理効率)が低下します
コード(クラスモジュールHTMLEntity)
' require VBScript.RegExp, Scripting.Dictionary Option Explicit Private m_regex_encode As Object ' VBScript.RegExp Private m_regex_decode As Object ' VBScript.RegExp Private m_regex_decodehex As Object ' VBScript.RegExp Private m_regex_decodedec As Object ' VBScript.RegExp Private m_entity2char As Object ' Scripting.Dictionary Private m_char2entity As Object ' Scripting.Dictionary Private Function RegExp(pattern As String, Optional g As Boolean = False, _ Optional i As Boolean = False) As Object Set RegExp = CreateObject("VBScript.RegExp") With RegExp .pattern = pattern .Global = g .ignorecase = i End With End Function Private Sub Class_Initialize() Dim t As String Dim m As Object ' match Dim name As String Dim value As String Set m_regex_encode = RegExp("([""&<>])", g:=True) Set m_regex_decode = RegExp("&([\w#][\w\d]*);?", g:=True) Set m_regex_decodehex = RegExp("#[xX]([0-9a-fA-F]{1,4})") Set m_regex_decodedec = RegExp("#(\d{1,5})") Set m_entity2char = CreateObject("Scripting.Dictionary") Set m_char2entity = CreateObject("Scripting.Dictionary") ' ISO 8859-1 t = "" _ & "nbsp 160 iexcl 161 cent 162 pound 163 curren 164 " _ & "yen 165 brvbar 166 sect 167 uml 168 copy 169 " _ & "ordf 170 laquo 171 not 172 shy 173 reg 174 " _ & "macr 175 deg 176 plusmn 177 sup2 178 sup3 179 " _ & "acute 180 micro 181 para 182 middot 183 cedil 184 " _ & "sup1 185 ordm 186 raquo 187 frac14 188 frac12 189 " _ & "frac34 190 iquest 191 Agrave 192 Aacute 193 Acirc 194 " _ & "Atilde 195 Auml 196 Aring 197 AElig 198 Ccedil 199 " _ & "Egrave 200 Eacute 201 Ecirc 202 Euml 203 Igrave 204 " _ & "Iacute 205 Icirc 206 Iuml 207 ETH 208 Ntilde 209 " _ & "Ograve 210 Oacute 211 Ocirc 212 Otilde 213 Ouml 214 " _ & "times 215 Oslash 216 Ugrave 217 Uacute 218 Ucirc 219 " _ & "Uuml 220 Yacute 221 THORN 222 szlig 223 agrave 224 " _ & "aacute 225 acirc 226 atilde 227 auml 228 aring 229 " _ & "aelig 230 ccedil 231 egrave 232 eacute 233 ecirc 234 " _ & "euml 235 igrave 236 iacute 237 icirc 238 iuml 239 " _ & "eth 240 ntilde 241 ograve 242 oacute 243 ocirc 244 " _ & "otilde 245 ouml 246 divide 247 oslash 248 ugrave 249 " _ & "uacute 250 ucirc 251 uuml 252 yacute 253 thorn 254 " _ & "yuml 255" ' Mathematical, Greek and Symbolic (1/2) t = t & " " _ & "fnof 402 Alpha 913 Beta 914 Gamma 915 " _ & "Delta 916 Epsilon 917 Zeta 918 Eta 919 Theta 920 " _ & "Iota 921 Kappa 922 Lambda 923 Mu 924 Nu 925 " _ & "Xi 926 Omicron 927 Pi 928 Rho 929 Sigma 931 " _ & "Tau 932 Upsilon 933 Phi 934 Chi 935 Psi 936 " _ & "Omega 937 alpha 945 beta 946 gamma 947 delta 948 " _ & "epsilon 949 zeta 950 eta 951 theta 952 iota 953 " _ & "kappa 954 lambda 955 mu 956 nu 957 xi 958 " _ & "omicron 959 pi 960 rho 961 sigmaf 962 sigma 963 " _ & "tau 964 upsilon 965 phi 966 chi 967 psi 968 " _ & "omega 969 thetasym 977 upsih 978 piv 982 bull 8226 " _ & "hellip 8230 prime 8242 Prime 8243 oline 8254 frasl 8260 " _ & "weierp 8472 image 8465 real 8476 trade 8482 alefsym 8501 " _ & "larr 8592 uarr 8593 rarr 8594 darr 8595 harr 8596 " _ & "crarr 8629 lArr 8656 uArr 8657 rArr 8658 dArr 8659 " _ & "hArr 8660 forall 8704 part 8706 exist 8707 empty 8709 " _ & "nabla 8711 isin 8712 notin 8713 ni 8715 prod 8719 " _ & "sum 8721 minus 8722 lowast 8727 radic 8730 prop 8733 " _ & "infin 8734 ang 8736 and 8743 or 8744 cap 8745 " _ & "cup 8746 int 8747 there4 8756 sim 8764 cong 8773 " _ & "asymp 8776 ne 8800 equiv 8801 le 8804 ge 8805 " _ & "sub 8834 sup 8835 nsub 8836 sube 8838 supe 8839 " _ & "oplus 8853 otimes 8855 perp 8869 sdot 8901 lceil 8968 " ' Mathematical, Greek and Symbolic (2/2) t = t & " " _ & "loz 9674 spades 9824 clubs 9827 hearts 9829 diams 9830 " _ & "rceil 8969 lfloor 8970 rfloor 8971 lang 9001 rang 9002 " ' Special t = t & " " _ & "quot 34 amp 38 lt 60 gt 62 OElig 338 " _ & "oelig 339 Scaron 352 scaron 353 Yuml 376 circ 710 " _ & "tilde 732 ensp 8194 emsp 8195 thinsp 8201 zwnj 8204 " _ & "zwj 8205 lrm 8206 rlm 8207 ndash 8211 mdash 8212 " _ & "lsquo 8216 rsquo 8217 sbquo 8218 ldquo 8220 rdquo 8221 " _ & "bdquo 8222 dagger 8224 Dagger 8225 permil 8240 lsaquo 8249 " _ & "rsaquo 8250 euro 8364" For Each m In RegExp("([\w][\w\d]*)\s(\d+)\s?", g:=True).Execute(t) name = m.submatches(0) value = ChrW(m.submatches(1)) m_entity2char.Add name, value m_char2entity.Add value, name Next End Sub Public Function encode(s As String) As String Dim p As Integer Dim str As String Dim m As Object ' match p = 0 str = "" For Each m In m_regex_encode.Execute(s) If p < m.firstindex Then str = str & Mid(s, p + 1, m.firstindex - p) End If str = str & "&" & m_char2entity.Item(m.submatches(0)) & ";" p = m.firstindex + m.Length Next str = str & Mid(s, p + 1) encode = str End Function Public Function decode(s As String) As String Dim p As Integer Dim str As String Dim m As Object ' match Dim c As String p = 0 str = "" For Each m In m_regex_decode.Execute(s) c = m.submatches(0) If p < m.firstindex Then ' 実体参照が現れる位置までの文字列をコピーする str = str & Mid(s, p + 1, m.firstindex - p) End If If m_entity2char.Exists(c) Then ' 文字実体参照 str = str & m_entity2char.Item(c) Else With m_regex_decodehex.Execute(c) If .Count Then ' 数値文字参照16進 str = str & Chr(val("&h" & .Item(0).submatches(0))) Else With m_regex_decodedec.Execute(c) If .Count Then ' 数値文字参照10進 str = str & Chr(.Item(0).submatches(0)) Else ' 文字実体参照でも数値文字参照でもない str = str & c End If End With End If End With End If p = m.firstindex + m.Length Next str = str & Mid(s, p + 1) decode = str End Function 'EOF
例
Dim o As New HTMLEntity Debug.Print o.decode("&") Debug.Print o.decode("&"<>") Debug.Print o.decode("A&") Debug.Print o.decode("A&B") Debug.Print o.decode("&B") Debug.Print o.decode("ABC") Debug.Print o.decode("ABC") Debug.Print o.decode("ABC") ' 実体参照を含まない Debug.Print o.decode("†‡") ' Debug.Print o.decode("A&B") ' 末尾に「;」がない Debug.Print o.decode("あいうえ") ' 日本語 Debug.Print o.decode("あ&い") ' 日本語 Debug.Print o.decode("あ&い") ' 末尾に「;」がない Debug.Print Debug.Print o.encode("&") Debug.Print o.encode("&""<>") Debug.Print o.encode("A&") Debug.Print o.encode("A&B") Debug.Print o.encode("&B") Debug.Print o.encode("ABC")
例の実行結果
ほかの方法
おそらく専ら問題になるのはデコードだと思います。正規表現を使わない方法となると,実体参照の種類だけReplace関数を実行するしかないように思えます。性能面でかなり問題が出るのではないでしょうか。
BASICって,そもそも文字列処理が得意ではない気がするので,あまり無理をすると不幸になる可能性が大です。どこからか実体参照を扱うCOMを調達した方がよいでしょう。
関連リンク
2006-10-01 Excel VBA漂流記の構築を開始しました
「Excel VBA漂流記」はExcel VBAをいじっていて,困ったり奇妙だなと思ったりしたことを書き綴ったサイトです。
計画当初,Microsoft Officeの新しいバージョンの動向がよく分かりませんでした。「作ってもだれも見ないのでは」という恐れがありました。Office12でもVBAは存続するそうですので,決行することにしました。
独自色を出すのが難しい
サイトの方向性を考えることにします。
この手の「ちょっとしたメモ」のサイトはいくつかあります。無数というほど沢山ではありませんが,すでに似たような情報を公開している人は大勢いるのです。
求められているのは,市販されている書籍には載っていない情報だと考えられます。たとえば仕様にはない動作に関する情報。立場により人はその動作を「バグ」と言ったり,「実装仕様」と言ったりします。
またたいていの書籍は機能の断片と,ごく小規模なアプリケーションの説明しかしていません。もともとVBAの用途はExcelの機能をちょっとだけ拡張するというもののようですので,当然といえば当然なのです。
さて昨今のプロセッサの処理能力の向上により,わりと大きなアプリケーションも動かせるようになってきました。ところが小物以上のアプリケーションをどうやって作るのか,といった情報はほとんど見かけません。
そこでExcel VBA漂流記では,以下の二点に重点を置くことにします。
- 好ましくない仕様の分析と回避方法
- 中規模から大規模なアプリケーションのための技法
あくまで「目標」なので,必ずこのとおりにするというわけではありません。
CMSにYukiWikiを使用
ただいまYukiWikiで実装検証をしています。
Wikiの詳しい説明は省略しますが,普通Wikiでは不特定多数の人が自由に内容を書き換えることができます。
Wikiはイタズラされ放題です。仮にイタズラされることがあっても「澱みは自然に浄化される」という発想なのですが,浄化されるのは流れのある箇所だけです。滅多に見ないようなページは,澱んだままになってしまう危険があるのです。
またWikiを狙ったSPAMも出てきているらしく,まったくもって予断を許しません。
作業計画
- 方針作成
- 内容検討
- 方式検討 ← 【いまここ】
- 構造決定
- ローカルサーバ構築
- 仮データ作成
- リモートサーバ構築
- データ移植
- 正式公開
「正式公開は11月末日あたりに」と思っていますが,どうなることやら。
2006-03-06 Excel X for MacでChartオブジェクトのExportメソッドが機能しない
※「Excel VBA漂流記:Macintoshプラットフォーム固有の問題」でまとめるつもりでしたが,小出しにすることにしました。
現象
Excel X for MacでChartオブジェクトのExportメソッドを使って,グラフを画像ファイルにしようとしたら「実行時エラー’1004’:’Export’メソッドは失敗しました : ‘_Chart’ オブジェクト」というエラーが発生してしまいました。
おそらく回避できない問題
Excel X for Mac(Office v. X for Mac)ではChartオブジェクトのExportメソッドは使用不可のようです。Office v. X for Macはエクスポート用のグラフィックフィルタをひとつも持っていないからです。
この問題を回避・代替する方法はたぶんありません。
Office v. X for Macのグラフィックフィルタ
オンラインヘルプにてExportメソッドを調べてみると,有効なFilterNameの例は「GIF,JPEG,PNG」だとしています。さらに「Macintoshではエクスポート用のグラフィックフィルタは,Microsoft Office X/Shared Applications/Graphic Filtersフォルダにある」と書かれています。
実際に「Macintosh HD:Microsoft Office X:Shared Applications:Graphic Filters:」を開いてみたところ,「EPS Import」と「Metafile Import」というふたつのグラフィックフィルタが存在していました。
名前を信用すると,これらのグラフィックフィルタはインポートのみでエクスポートする機能はありません。
メモ
- Excel 2004(Office 2004 for Mac)もたぶん同じ問題を抱えています。同じ現象が発生するはずです
- 古いバージョンのOfficeはグラフィックフィルタを持っています。Office 2001 for Macには「GIF Import & Export,JPEG Import & Export,PNG Import & Export」があります。Mac OS Xで動くグラフィックフィルタは提供されなかったということなのでしょう
リンク
- [OFF2001] Office 2001 の完全インストールでインストールされるファイル (パート 1)
- [OFFX] Office v. X for Mac の完全インストールでインストールされるファイル (パート 1)
2005-12-19 Visual Basic6.0処理系の感想
Visual Basic6.0処理系(以下VBと表記)を使い始めて5か月ほどが経過しました。だいたい使えるようになったので感想をお話します。
【注意】実際に使っていたものはExcel VBAです。細かい説明をすると長くなるのでVBA≒VB6.0とお考えください。なおVB.NETは別ものなのであしからず。
VBは遅いか
巷では「VBは遅い」であるとか「VBで出来たソフトは不出来」という評判をよく耳にします。さらには「VBでソフトを作っている人間は無能」という乱暴な意見すら散見されます。確かにVBで作られたフリーソフトや業務用アプリケーションの中には反応が鈍かったり,画面の描画が欠けたりするものが存在します。
私はVBがインタプリタなのと,紛いにもBASICなので「遅くて使い物にならないのでは」と懸念していました。
実際に使ってみると,計算量のオーダーをきちんと意識して設計すれば遅くなりませんでしたし,システムに再描画の機会を適切に与えれば画面がおかしくなることもありませんでした。たとえば大量のレコードを探索するときは,ハッシュテーブルを使って計算量を減らす工夫をすれば実時間で処理が終わります。
いまどきのプロセッサはとんでもなく速いので,インタプリタだからといって支障が出るほど遅いなんてことはないのです。
関数ポインタの代替方法
VBにはポインタがありません。ポインタ型そのものはありませんが,オブジェクトの変数は暗黙で参照型ですし,プリミティブ型をサブルーチンやメソッドの引数に使う場合は値渡しと参照渡しを選ぶことができます。
「うーむ」と考え込んでしまったのは,関数ポインタ(実行コードの位置を指し示す)が使えないことでした。
並び替えのサブルーチンがあったとして,順序を返す関数をどうやって実装するのかちょっと悩みました。ところで関数ポインタが存在しないのはJavaも同じです。
Javaではインターフェイスにコールバックさせるメソッドを定義して,呼び出し元にはインターフェイスを実装したオブジェクトの参照を持たせるのが常套手段です。
VBも同じ発想でコールバックが実現できます。
例外処理
いちばん気になったのは例外処理です。VBにはtry-catch-finally構文が存在しないので,これに替わる手段を使わなければなりません。
try-catchの代替には「On error resume next」とif文による条件分岐を使います。VBにはシングルトンのErrオブジェクトというものがあり,エラーが発生するとErr.number属性にエラー値が代入されます。たとえばサブルーチンを呼び出した直後にif文でErr.numberの値を判定して,0以外であればサブルーチン内でエラーが発生したということになるのです。
私はfinallyの美しい換言案をまだ発見していません。ファイルを開いたときは,処理が成功しようが失敗しようが,途中でサブルーチンから抜けようがとにかく最後にはファイルを閉じたいということがよくあります。そんなときはfinallyの中でファイルを閉じておけば確実なのですが,VBではできないのです。
もちろんファイルを開いた後の処理を別のサブルーチンにしておいて,サブルーチンから抜けたらファイルを閉じる,という構造にすればfinallyの替わりにできそうです。でもこういう書き方は悪文になると思います。
2005-11-20 Excel VBAの本の感想をまとめて
「サラサーティ1」の開発に際して,Microsoft Excelについてさまざまな調査をしました。今回の取り組みではExcel VBA(Visual Basic for Applications)を初めて使ったので,Visual Basicの文法からExcelのオブジェクトモデル,既知の問題まで幅広く情報収集しなければなりませんでした。
情報収集の際に何度も本屋さんに足を運びました。今日は市販されているExcelとVBAの書籍の感想をお話します。
EXCEL VBA コーディング・テクニック
(間 顕次著,毎日コミュニケーションズ,2002.8,ISBN 4-8399-0739-0)
初めて買った本です。最初はどんな本を選べば良いのかさっぱり分からなかったので,適当に買ってしまいました。
この本は買うだけ無駄のようです。例題はかなり実践的なのですが,「フォームにコントロール(GUI部品)をべたべた貼ってみました」という世界からの展開がありません。小物以上のマクロを作りたい人にとっては物足りないのです。
ここが知りたかった! Excel VBA 500の技
(Windowsプログラミング愛好会 著,技術評論社,2005.6,ISBN 4-7741-2414-1)
網羅性は高いのだが,極端に底が浅いです。分からないことを解決する糸口を見つけるのには役に立ちますが,決して糸は解けません。
Excel VBAの機能はものすごく多いので,どんな機能があるのか大雑把に知りたい人にとっては便利だと思います。
それから初版だからかもしれませんが,誤字・脱字がとても目立ちました。
Excel Hacks プロが教える究極のテクニック100選
(David Hawley,Raina Hawley著,羽山 博 監訳,2004.10,オライリー・ジャパン,ISBN 4-87311-205-2)
お勧めの一冊です。VBAとExcel数式を使った恐ろしい技がつぎつぎ出てきます。何気なく通りすぎて読み返してみると「おおっ」と来ます。
ただ完全性がないというか,柔軟性にやや欠ける気がしました。
例えば「勝手に広がる名前付き範囲」では,あらかじめ大雑把な行数をハードコード(直書き)しなければなりません。何ひとつ矛盾がなく,美しく整理された世界に焦れている人にとって数値が固定されているなんて,とても許されることではありません。
でも実際のExcelの利用現場を見ると,「阿漕」だとか「邪道」なんて言っている場合ではありません。「最終的にA4用紙からはみ出ないで印刷できればいい」というときには,数値が固定だろうが可変だろうが,セルの参照が絶対だろうが相対だろうが,そんなことはどうでいいのです。
経済・金融分析のためのVBAプログラミング
(原田 康平 著,牧野書店,2000.10,ISBN 4-7952-0136-6)
お勧めの一冊です。章立てがしっかりしており,学校で使う教科書みたいな書き方をしています。学術書に慣れている人にとってはかなり読みやすいと思います。
コンピュータ業界の人にとっては常識みたいな事柄も丁寧に書かれています。プログラミングの経験がまったくない人でも,自力で読み進めることができるでしょう。
ただこの本はお金の計算を目的としており,用途がかなり限定されます。また対象としているExcelのバージョンは「2000」ですので,やや古い感じがします。
Excelデータ分析[増補版]
(I/O編集部 著,工学社,2005.1,ISBN 4-7775-1096-4)
この本はVBAの本ではありません。Excelの統計関数を説明した本です。かなり平坦な言葉で書かれているので,統計の知識がなくても読むことができます。
数学の本って表記が難解というか「数式に使われている記号の意味すら分からない」なんて困ったことになりがちです。この本は,高校数学の知識があれば読めるように工夫されているらしく,極端な拒絶反応は起こりにくいようです。
2005-09-09 Excel VBAで改行コードがLFのファイルを読む
Excel VBAで,CRLF以外の改行コードが含まれたテキストファイルを読み込むコードを作りました。
あらまし
VBAではLine Input # ステートメントを使うと,シーケンシャルファイルから1行ずつ読み込むことができます。
ところで,改行コードがLFのファイルを読み込ませてみたら,Excelが応答しなくなってしまいました。 Line Input # ステートメントは,改行コードがLFのファイルには対応していないようです。
そこでCRLF,LF,CRの三種類の改行コードに対応したコードを作ってみました。
動作概要
- ファイルをバイナリモードで読み出した後,改行コードを認識し1行の文字列に変換する
- バッファを設けて読み出しの効率化を図る
仕様
- 認識する改行コード列はCRLF,LF,CRの三種類
- ファイルの末尾に改行コードがなかった場合にも対応
- MacのVBAに対応
注意事項
- このコードは無保証です
- 細かな挙動は不明です。巨大なファイル,1行がやたらと長いファイル,そもそも改行が一つもないファイルなどを読み込んだ場合にどんな挙動をするか明らかではありません
- VBA歴の浅い人が書いたので,VBAっぽくないコードかもしれません
コード
Const FILEBUFSIZE = 32767 Dim CR As String CR = Chr(13) #If Not Mac Then CR = StrConv(CR, vbFromUnicode) #End If Dim LF As String LF = Chr(10) #If Not Mac Then LF = StrConv(LF, vbFromUnicode) #End If Dim FileNum As Variant FileNum = FreeFile() Open "filename" For Binary Access Read As FileNum Len = FILEBUFSIZE Dim byteBuf(FILEBUFSIZE - 1) As Byte Dim strBuf As String strBuf = "" Dim FileSize As Long FileSize = LOF(FileNum) Do Until EOF(FileNum) Get FileNum, , byteBuf Dim SeekPoint As Long SeekPoint = Seek(FileNum) - 3 If SeekPoint <= FileSize Then strBuf = strBuf & CStr(byteBuf) Else strBuf = strBuf & LeftB(CStr(byteBuf), FILEBUFSIZE - (SeekPoint - FileSize)) End If Dim p1 As Long p1 = 0 Dim p2 As Long p2 = 0 Do p1 = InStrB(1, strBuf, CR, vbBinaryCompare) p2 = p1 If p1 <> 0 Then If LenB(strBuf) < p1 + 1 Then p1 = 0 ElseIf MidB(strBuf, p1 + 1, 1) = LF Then p2 = p2 + 1 End If Else p1 = InStrB(1, strBuf, LF, vbBinaryCompare) p2 = p1 End If If p1 = 0 And EOF(FileNum) And LenB(strBuf) > 0 Then p1 = LenB(strBuf) p2 = p1 End If ' If p1 <> 0 Then Dim head As String Dim tail As String head = MidB(strBuf, 1, p1 - 1) tail = MidB(strBuf, p2 + 1) #If Not Mac Then head = StrConv(head, vbUnicode) #End If Dim CurrentLine As String CurrentLine = head Debug.Print CurrentLine strBuf = tail End If Loop While p1 <> 0 Loop Close FileNum
ほかの方法
(1) FileSystemObjectオブジェクトのReadLineメソッドも,改行コードLFに対応しているそうです(伝聞なので検証なし)。現在は,このFileSystemObjectオブジェクトを使う方法が主流なのかもしれません。
(2) Excelの機能である「外部データの取り込み」を使うと,シートに任意のテキストファイルを読み出すことができます。この機能では改行コードLFのファイルも読めます。VBAヘルプでQueryTablesオブジェクトを調べてみてください。
メモ
- 改行コードの種類。WindowsのVBAの改行コードはCRLF(0x0d-0x0a),MacのVBAの改行コードはCR(0x0d)です
- 文字コード。VBAが出力するテキストファイルの文字コードは,CP932の「はず」です。CP932はSHIFT-JISに拡張文字(たとえば丸で囲んだ数字)を追加した文字コードです
- Unicode。WindowsのVBAでは内部の文字コードをUnicodeで扱っています。テキストファイルをバイナリファイルとして読み出した場合,その文字列はUnicodeとして扱われません。文字列の比較ならびに出力する際は,明示的に文字コードを変換しなければなりません。MacのVBAはUnicodeを採用していないので,文字コードの変換は不要です
- GETステートメント。GETステートメントは,常にOpenステートメントで指定したバッファ容量を読み出します。ファイルの末尾だからといって読み出す容量が減ることはありません。ファイル容量を超えて読み出したデータは切り捨てなければなりません