[三流君] −−> [プログラマー業務の愚痴] −−> [バックナンバー一覧]
−−> No.169 労力は少なく 汎用性を持った関数、データの外だし

労力は少なく 汎用性を持った関数、データの外だし


本文(発行内容)


<労力は少なく 汎用性を持った関数、データの外だし>

こんにちは、三流プログラマーのKen3です。 まだ、つぶされずに生き残ってます(笑) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ そんな前フリは置いといて、 今回は、 汎用性を持った関数 と データは外に出そうよ って話です。 まぁ、いつもの独り言だけど、聞いてください。

/* * 1.今回のキッカケ */

No.167 Ctrl+C + Ctrl+V を使う前に一呼吸置こうよ http://www.ken3.org/backno/backno_guchi33.html#167 で、 コピー、貼り付けでのプログラムを作る前に、 一呼吸置いて考えましょうよ、、 って感じのことを書きました。 今回は、もう一歩進んで、違う方向から、 労力を減らすために、汎用性を持った関数の作り方 インクルードファイルを使って、変更は一箇所で済ませる方法 など、 いつもの三流プログラマーの語りから、何かをつかんでくれれば幸いです。

/* * 2.サービス?で流行っていない有料版のコピー */

有料版で作成・解説してたサンプルなんだけど、 http://www.ken3.org/p/lzh/off004.lzh に Book-004.xlsが保存されてます。 汎用性? ~~~~~~~~ プログラムが組めるようになってくると、修正のしやすさや(労力をかけたくない)、 流用の効くプログラムの書き方、、、などで差がでてきます。 私もあまり将来流用可能なプログラムを組んでないので、 偉そうなこと言えないんだけど(笑) 前回、フォルダー名を貰い、そのファイル名をセルにセットする。 なんて処理を作りましたよね。 '引数(パラメータ)でフォルダー名をもらい、 'データをA列にセットする
Sub setFILELIST(strFolder As String)

    Workbooks.Add   '新しいブックを追加

    Dim strFileName As String  'ファイル名
    Dim nYLine      As Integer '行カウンタ

    '最初のファイル名を取る
    strFileName = Dir(strFolder & "\*.*", vbNormal)
    
    'ファイルが見つからなくなるまでループしてデータをセットする
    nYLine = 1
    Do While strFileName <> ""   ' ループを開始します。
        Cells(nYLine, 1) = strFileName 'セルにファイル名をセットする
        Cells(nYLine, 2) = strFolder & "\" & strFileName
        nYLine = nYLine + 1      ' カウントアップする
        strFileName = Dir        ' 次のファイル名を返します。
    Loop

End Sub
ざっと見ると、できてるんだけど、 変更が来た時、流用が効きにくいです。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ えっ、どこが? まぁまぁ、これから書くので、あせらないで。 1つの考え方、固定処理をパラメーターにする ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ フォルダーからファイル名を取得して、データをセットしてました。 *.jpg や *.xls とファイルの指定をして取出したくなったら? コピー君の考え方は、 '最初のファイル名を取る strFileName = Dir(strFolder & "\*.*", vbNormal) この部分を、"\*.*""\*.xls"と指定ファイルに変える方法があります が、 そんなことやってたら、*.bmpがほしい、*.htmlが、、、 と 種類別に関数が増えてしまいます。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ※まぁ、ボクはコピー操作が得意だし、間違えないから平気だよ  って人は、置いといて、、、 そんな時は、フォルダーと一緒にファイルパターンもパラメーターで 貰うようにします。 Call setFILELIST(strFolder, "*.*") 'データのセット ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ とファイル名とパターンで関数を呼ぶようにします。 ※関係ない話だけど、\*.*←が顔文字に見えたアナタ、重症だよ って書くってことは、Ken3がそんな風に感じたんだよね  ギクっ、、バレたか・・・ '引数(パラメータ)でフォルダー名とファイルの種類をもらい、 'データをA列にセットする
Sub setFILELIST(strFolder As String, strPattern As String)

    Workbooks.Add   '新しいブックを追加

    Dim strFileName As String  'ファイル名
    Dim nYLine      As Integer '行カウンタ

    '最初のファイル名を取る
    strFileName = Dir(strFolder & "\" & strPattern, vbNormal)
    
    'ファイルが見つからなくなるまでループしてデータをセットする
    nYLine = 1
    Do While strFileName <> ""   ' ループを開始します。
        Cells(nYLine, 1) = strFileName 'セルにファイル名をセットする
        Cells(nYLine, 2) = strFolder & "\" & strFileName
        nYLine = nYLine + 1      ' カウントアップする
        strFileName = Dir        ' 次のファイル名を返します。
    Loop

End Sub
たんに、 setFILELIST(strFolder As String, strPattern As String) と関数の受け取りのパラメータが増えて、 strFileName = Dir(strFolder & "\" & strPattern, vbNormal) で、指定してるだけなんですね。 関数の機能を少なくしてシンプルにする ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ もう一つのアプローチ方法として、 関数の機能を少なくしてシンプルにして 汎用性を持たせる方法があります。 ^^^^^^ なんか回りくどく説明してますが、 余計な機能がついていないほうが、 組み合わせで使える幅が増えます。 '引数(パラメータ)でフォルダー名とファイルの種類をもらい、 'データをA列にセットする setFILELIST(strFolder As String, strPattern As String) この関数、 ・フォルダー内をパターンで検索して、 ・ファイル名を新規のブックに保存します。 と、検索とデータセット、2つの機能が入ったお得な関数です。 どこが得なんだよ、、 オレは、ファイル名だけほしいのに、、、なんて時ありますよね。 ※セットじゃなくて、単品がほしいんだよ、単品が。 新規ブックに保存する処理がジャマなんですねとても。 その通り、携帯は通話だけできれば十分、えっ写メールは必要だって? まぁ、1つで何でもできるのもいいけど、 プログラムの場合、組み合わせの時、邪魔になるときがあります。 あまり分割し過ぎも、バラバラで組み合わせや管理が大変なのですが、 よく使う共通関数は、1関数、1機能、なんてシンプルに作ってみると、 利用し易いです。 ※最低限を作成して、足りないところに外側から肉付けする。 試しに 配列にファイル名をセットする関数を作ってみます。 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ '引数(パラメータ)でフォルダー名とファイルの種類をもらい、 'データを受け取った配列にセットする
Sub setFILELIST(strFNBOX() As String, _
                strFolder As String, strPattern As String)

    Dim strFileName As String  'ファイル名
    Dim n As Integer           '配列の要素数

    n = 1              '初期化
    ReDim strFNBOX(n)  '配列の数を動的に変える

    '最初のファイル名を取る
    strFNBOX(n) = Dir(strFolder & "\" & strPattern, vbNormal)

    'ファイルが見つからなくなるまでループしてデータをセットする
    Do While strFNBOX(n) <> "" ' ループを開始します。
        n = n + 1              ' カウントアップする
        ReDim Preserve strFNBOX(n) ' 配列の数を動的に変える
        strFNBOX(n) = Dir      ' 次のファイル名を返します。
    Loop

End Sub
見なれない書き方ですが、まず配列を受け取ってます。 Sub setFILELIST(strFNBOX() As String, _ strFolder As String, strPattern As String) strFNBOX()と数を指定しない受け取り方です *ファイル名がいくつになるか不明なので。 次のポイントが ReDim strFNBOX(n) ReDim Preserve strFNBOX(n) ' 配列の数を動的に変える です、これは、普通はDim A(10)など配列の数を指定するのですが、 動的に好きな数に配列のサイズを取ります。 Preserveのキーワードは、前のデータを残してサイズを拡張する、 ^^^^^^^^ 今回のような処理の時に使います。 ※サイズを増やしながらデータを追加していくイメージなので、  サイズ変更前のデータを残しながら処理してます。 Do While strFNBOX(n) <> "" ' ループを開始します。 n = n + 1 ' カウントアップする ReDim Preserve strFNBOX(n) ' 配列の数を動的に変える strFNBOX(n) = Dir ' 次のファイル名を返します。 Loop と、配列を拡張しながらファイル名をセットします。 分割した表示部は、 'フォルダー名とファイル名配列を受け取り、シートを新規作成
Sub make_data(strFolder As String, strFN() As String)

    Dim nYLine      As Integer '行カウンタ
    
    Workbooks.Add   '新しいブックを追加

    For nYLine = 1 To UBound(strFN)  'ファイル名をセットする
        Cells(nYLine, 1) = strFolder & "\" & strFN(nYLine)
    Next nYLine

End Sub
と、フォルダー名、ファイル名の配列を受けとって、 新規ブックにファイル名を書き込んでます。 ここで、おっ?と思うのは、 For nYLine = 1 To UBound(strFN) 'ファイル名をセットする Cells(nYLine, 1) = strFolder & "\" & strFN(nYLine) Next nYLine の部分の、UBound(strFN)です。 UBoundに配列を渡すと、インデックス番号の最大値を返してくれるので、 ^^^^^^これを利用してループを作ってます。 よく、文字列分割の関数 Split関数と組み合わせてUBound関数を使ったりしてます http://www.ken3.org/cgi-bin/test/test024-2.asp ポイントは、実行時に配列の要素数が変化しているので、 その最大値をもらって、処理してます。 メインルーチンは、
Sub Main()

    Dim strFolder As String '選択されたフォルダーを格納
    Dim strBOX()  As String 'ファイル名格納用変数

    'フォルダーを選択させる
    strFolder = getFOLDER()  'フォルダーの選択関数を呼ぶ

    'キャンセルだったら処理を抜ける
    If strFolder = "キャンセル" Then
       Exit Sub
    End If

    '選択されたフォルダーを表示関数に渡し表示する
    Call setFILELIST(strBOX(), strFolder, "*.*") 'データのセット
    
    '新規のシートにデータをセットする
    Call make_data(strFolder, strBOX())

End Sub
と修正しました。 ポイントは、 Dim strBOX() As String 'ファイル名格納用変数 配列のサイズを指定しない定義方法、 と Call setFILELIST(strBOX(), strFolder, "*.*") 'データのセット Call make_data(strFolder, strBOX()) の関数の呼び方です。 配列変数に一度ファイル名を全て保存します で、その配列からシートにデータをセットしてます。 一回配列に保管するのがムダな場合もあるが、 機能が分かれていると、 Call setFILELIST(strBOX(), strFolder, "*.CSV") 'データのセット でCSVのファイル名を取得、 For n = 1 To UBound(strFN) 'ファイルをインポート strIN = strFolder & "\" & strFN(nYLine) strINを使用してインポート Next nYLine なんて少し変更した処理も比較的簡単に作成することができます。 シンプルな汎用性のある共通関数作りにもチャレンジしてみてください。 機能を分割すると、汎用性のあるプログラムが書けることが、 なんとなくわかったと思います。 Dim FN() As String Call setFILELIST(FN(), strFolder, "*.jpg") 'データのセット で、ファイルリストが取りたい時などに使える関数になりました。 (*標準関数に少し肉付しただけなんですが(笑)) 何かの参考となれば幸いです。 プログラム作りは簡単で面白いなぁと感じるような 解説/メールマガジンを書きたいと思ってます。

/* * 3.外部ファイルに広告データを持ち、楽に差し替える方法 */

今度は、ASP系で書いたネタ、 テキスト広告のローテーションを作ってみたくて(笑) いろいろと試行錯誤した結果を兼ねて、ASP系のネタにしてみました。 #Include File で、ファイルをインクルードする ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ASPと言っても、通常は、HTML内に<% 〜 %>でスクリプトを埋め込んでます。 a.asp <% ASP の処理A %> <html> <head> </head> <body> ヘッダ部分に目次へのリンクなど 本文 <% ASP の処理B %> フッダ、広告など <% ASP の処理C %> </body> </html> <% ASP の処理D サブルーチンなど %> まぁ、書き方のキレイさ(見易さなど) 位置によっていろいろとあるのですが、 こんな感じです。 大体、HPを作成する時、構成を決めます。 ---- 上部 HPタイトルと目次、掲示板へのリンク、、 本文があって 下部 リンクを書く人や小金稼ぎのバナー広告 ---- まぁ、わかりやすく、こんな構成だとします。 すると、上部のHTMLと下部のHTMLは変わらないんですね。 なので、ひとつの方法は、雛形のHTMLファイルを作っておいて、 それを別名でコピーして修正する、そんな方法です。 ※私も使ってます。 まぁ、コピー君するとしても、コピーしやすく雛形を作っておくんですね。。。 この方法でも良いのですが、 2・3ヶ月たってくると、広告を差し替えたいなぁ、 新しいカテゴリできたので、タイトルにリンクを増やしたい・・・ と共通だったはずのヘッダ、フッダを修正する時があります。 コピー操作が得意な若者だったら、 40ファイルぐらい平気でコピー、貼り付けをして、 確認しないで客先に提出(だってコピーしただけなんで間違えないよオレ様は) コピー忘れや2重コピー(Ctrl+Vを2回押した?)など、 40ファイルもあるとミスします。 ※若くないKen3もたぶんミスするのでしょう。 そんな時に便利な方法が、 #Includeを使ってASPを作る方法です。 ※言語によって、書き方違うのですが、実装可能な言語が多いと思います。 使い方は簡単で、 <!-- #Include File="info.inc" --> と外部から挿入したいファイルを書くだけです。 具体的な使い方は、ASPだと、 <%@LANGUAGE=VBScript%> <html> <head> <title>ASP #Include File="xxxx.inc" でファイルをインクルード</title> </head> <body bgcolor=#ffffff text=#000000> <!-- #Include File="info.inc" --> <!-- ↑ヘッダの共通イメージをインクルード --> <h2>ASP #Include File="xxxx.inc" でファイルをインクルード</h2> test058-1.asp<br> #Include File="xxxx.inc"とファイルをインクルードして、<br> 共通のヘッダ、フッダを使う<br> <hr> [<a Href="info.inc" TARGET="_blank">info.incを開く</a>] ←使用したヘッダファイル<br> [<a Href="inc_mokuji.inc" TARGET="_blank">inc_mokuji.incを開く</a>] ←使用したフッダファイル<br> <!-- #include file="inc_mokuji.inc" --> <!-- ↑フッダの共通イメージをインクルード --> </body> </html> ポイントは、 ~~~~~~~~~~~~ <!-- #Include File="info.inc" --> ↑ヘッダの共通イメージをインクルード <!-- #include file="inc_mokuji.inc" --> ↑フッダの共通イメージをインクルード なんだぁ、一行単純に書いてるだけなのね(笑) この単純に書いた一行の処理にしていると、 ヘッダやフッダのイメージを変えたい時は、 http://www.ken3.org/cgi-bin/test/info.inc http://www.ken3.org/cgi-bin/test/inc_mokuji.inc といったファイルの中身を変更するだけで、 実行時に読み込まれるので、表示内容を変更することが出来ます。 広告用のテキストファイルを用意して、そのファイルを挿入(インクルード)します。 新製品のPCが出たら、広告を差し替える。 効果の無い広告を簡単に差し替える(これが一番使うかな) なんてコトが簡単に出来ます。 http://www.ken3.org/cgi-bin/test/test058-1.asp でテストできます。イメージを確認してください。 ランダムにローテーションバナーを表示させたい ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ さてと、 #Include File を使うと、実行時にファイルを挿入可能なことがわかりました。 一歩進んだ要求だと(そんな要求私だけかもしれないけど) ランダムでバナー広告を切り替えて表示したい。 なんて、思うかもしれません。 乱数かぁ、、、 Randomize '乱数系を初期化 nNO = Int(Rnd * 10) で0〜9までの数を発生させられるので、 インクルードするファイルを http://www.ken3.org/cgi-bin/inc/hed0.inc http://www.ken3.org/cgi-bin/inc/hed1.inc http://www.ken3.org/cgi-bin/inc/hed2.inc   ・   ・ http://www.ken3.org/cgi-bin/inc/hed9.inc とバーナー広告を10種類用意しておいて、 切り替えてインクルードしてみたいです。 <% '頭で乱数の発生 Randomize '乱数系を初期化 nNO = Int(Rnd * 10) '0〜9までの乱数を発生させる strFNAME = "/cgi-bin/inc/hed" & nNO & ".inc" 'ファイル名を作る %> とファイル名を作ってから、 <!-- #include file="<%=strFNAME%>" --> で勝負、、あれれ、 Active Server Pages エラー 'ASP 0126' インクルード ファイルが見つかりません /cgi-bin/test/test058-2.asp, 行 22 インクルード ファイル '<%=strFNAME%>' が見つかりませんでした。 あっ、バカみたい、””で囲って文字列にしてるよ、 よし、””をはずして、 <!-- #include file=<%=strFNAME%> --> Active Server Pages エラー 'ASP 0126' インクルード ファイルが見つかりません /cgi-bin/test/test058-2.asp, 行 22 インクルード ファイル 'strFNAME' が見つかりませんでした。 できないのかなぁ、 まぁ、インクルードファイルが動的に切り替わる、、 なんて用途ないしね。 自分でファイルを開いて読みますか、 <% '自分でファイルを読む ' FileSystemObjectを生成します Set objFS = Server.CreateObject("Scripting.FileSystemObject") ' strFNAMEを読取専用モードで開きデータを読む Set ts = objFS.OpenTextFile(Server.MapPath(strFNAME), 1, True) Do While ts.AtEndOfStream = False 'ファイルの終端になってない間ループ strDATA = ts.ReadLine 'ファイルからデータを一行を読む Response.Write strDATA Response.Write vbCRLF '改行する Loop '使ったファイルは閉じようよ ts.close Set objFS = Nothing %> と素直に、テキストファイルを開いて1行読み込み、出力しました。 http://www.ken3.org/cgi-bin/test/test058-2.asp でテストできます。イメージを確認してください。 ポイントは ~~~~~~~~~~ 乱数の発生前に、 Randomize '乱数系を初期化 で 乱数系の初期化。 nNO = Int(Rnd * 10) strFNAME = "/cgi-bin/inc/hed" & nNO & ".inc" 'ファイル名を作る でファイル名を作ったら、 しかたなく自分でFileSystemObjectを生成して、 .ReadLineで一行読み込む、.AtEndOfStreamでファイルの終端チェック でした。 こんな感じで、 プログラム内に固定の文面を置いておくより、 変更があるデータは、ファイルとして外に置く。 実行時にそのデータファイルを参照する、 修正時はデータファイルのみを変更する。 三流君みたいな、コピー君をみなさんは、卒業してくださいね。

/* * 4.広告のローテーションバナー、あまり意味無いよ */

実は、広告のローテーションバナーって、あまり意味なかったりする。 HPの来客の状態にもよるけど。 私のHPへの来客の多くって、 メルマガ見てくるお客さんよりも(発行数600ぐらい)、 検索でHitして来る一見さんが多い。 検索で来る人って、探し物をして来る人ですよね。 当たり前でしょ(笑) そんな、エラーの原因を探したり、関数を調べている、 急いでいる人は、広告のバナーなんて、見ないんですよね。 同じ広告を見ても押さないだろうから、 広告をローテーションさせれば? と素人HP管理者は考えるけど、 実際は、違う広告を見ても、モトモト広告はクリックしないから、 意味無いんですね。 ところが、唯一意味がある場合があって、 えっ、気になる? どうしようかなぁ・・・たいしたことじゃないので、書いちゃうけど、 インターネットの一括ダウンロードソフトで、 設定に慣れてないのか?それとも光やADSLで気にしないのか? 広告ごと、まるごとHPを落としていく人がたまに居る。 広告をローテーションさせていると、そんな人が居た時に、 違う広告を落として行ってくれて、小金が稼げたりする(これホント) 広告会社、ダウンロードソフトは未チェックなのかなぁ。 ※インターネット忍者とかはダメですね。。。

/* * 5.終わりの挨拶(次回はアルのか?(爆)) */

よくわからなかったけど、何が今日は言いたかったの? えっと、 ・シンプルに汎用性をもった関数を作ってね ・外部にデータを置く、インクルードやファイル読み込みで共通データを読む ・広告のローテーション、あまり意味無いよ って話でした。 何か読者の心に残れば、うれしいです。 *私の独り言をうまく消化してくださいね。 いつも失敗?のKen3でした。 ~~~~~~~(↑オイオイ)


ページフッター

ここまで、読んでいただきどうもです。ここから下は、三流君のホームページの紹介・案内です
目的の情報が見つかったか?少々心配しつつ、、、

リンクや広告など

項目別に本音?それとも建て前?的な記事をまとめました。

気になったジャンル↓を選択してください。
[ルーキー rookies]・・・ 新人さん達 初心者さんへ
[学ぶ study]・・・学習、技術の取得
[仕様書 doc]・・・仕様書・設計書関係の話
[共同作業 team]・・・チーム、グループ作業
[プログラムは心? spirit]・・・プログラマー 心・気質・魂

[掲示板デビューしようぜ bbs]・・・掲示板関係の話、質問者・回答者の気持ちほか
[昔はできた seo]・・・三流式の効果無しSEOとアフィリエイト
[仕事や作業、転職 job]・・・仕事や転職、評価、作業など
[その他 etc]・・・その他 分類外の記事

※↑文章の味付けが変わっていて、お口に合うかわかりませんが。。。
※※読んで、気分を悪くされたらスミマセン。

Blogとリンク:[三流君の作業日記]/ [愚痴(Bookmark)]/ [広告Blog(Bookmark)]



[三流君(TOP ken3.org へ戻る)] / [プログラマー業務の愚痴] / [バックナンバー 一覧]