[[20150322143808]] 『word vbaからexcelを操作』(スズメ) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『word vbaからexcelを操作』(スズメ)

word vbaからexclを起動し、エクセルのセルに数値を書き込み、その書き込んだ文字列を昇順に並び替え、それを変数に格納し、エクセルブックを保存せずに閉じることは可能でしょうか?

私は、とりあえずセルに値を書き込むところまでやるつもりで、以下のコードをword vbaで実行しました。新規エクセルブックは作れましたが、オブジェクトが必要ですというエラーがでて、うまくいきませんでした。

Sub Macro2()
Dim b As String
Dim c As Long
Dim ex As Object
Dim d As String

    d = "C:\Users\Documents\aba"
    Set ex = CreateObject("Excel.Application")
    ex.Visible = True
    Set book = ex.Workbooks.Add
    b = Dir(d & "*.pdf")
    c = 0
    Do While b <> ""
        c = c + 1
        book.Cells(c, 1).Value = b
        b = Dir()
    Loop
    Set ex = noting
End Sub
どこがいけないのでしょうか?よろしくお願いします。

< 使用 Excel:Excel2007、使用 OS:Windows7 >


 >book.Cells(c, 1).Value = b

 book.sheets("Sheet1").Cells(c, 1).Value = b

 でしょうか。

(マナ) 2015/03/22(日) 15:11


ダメでした。
(スズメ) 2015/03/22(日) 15:22

どんなエラーですか?同じエラー?

(マナ) 2015/03/22(日) 15:31


>d = "C:\Users\Documents\aba"
¥がたりないとか

(マナ) 2015/03/22(日) 15:36


それが原因ではありませんでした。
(スズメ) 2015/03/22(日) 15:42

ですから、どんなエラーメッセージなのですか。

あと、Option Explicitを記載した状態で
エラーがでないコードを提示していただけるとよいです。

(マナ) 2015/03/22(日) 15:44


 横入り失礼。

 「ダメでした。」
 「それが原因ではありませんでした。」

 ほんとにQ/Aで解決しようとしてます?
 なぞなぞごっこをしてます?

 エラーになったコードとそのメッセージくらい提示するのは【最低限】必要なことですよ。

 それはさておき、

 >エクセルのセルに数値を書き込み

 書き込んでいるのは PDFファイル名じゃないんですか?

(β) 2015/03/22(日) 16:16


  >>エクセルのセルに数値を書き込み
  >書き込んでいるのは PDFファイル名じゃないんですか?

 そういうことですか。数値が書き込まれないということでしたか。
 こちらでは、A列にファイル名がちゃんと書き込まれていたので、不思議に思っていました。

 数値って何?というのが、新たな疑問ですが

(マナ) 2015/03/22(日) 16:35


すいません。

エラーになったコードがわからず、なおかつ何度もマクロを実行してもオブジェクトが必要ですというメッセージしか出なかったので、記述しようがなかったのです。あと、Option Explicitというのは知りませんでした。

それを書いてみた所、bookに黄色いマーカーがつき、変数が定義されていませんと出てきました。あと、notingのスペルミスが出来てきましたが、これを修正しても何も変化がありません。
(スズメ) 2015/03/22(日) 16:37


数値じゃなくてファイル名でしたね。

失礼しました。
(スズメ) 2015/03/22(日) 16:38


 Word VBA を書くのは初めてなんですが書いてみました。

 エクセル関連の変数記述には、やはり わかりやすい記述がいいと思いましたので、
 Microsoft Excel x.x Object Linrary を参照設定してあります。

 フォルダは、こちら側のテスト環境ですから、そこは実際のものに。

 エクセルを終了させた後、読み込んだPDFファイル名をメッセージで表示しています。

Sub Test()

    Dim xlApp As Excel.Application
    Dim wb As Workbook
    Dim sh As Worksheet
    Dim fName As String
    Dim fPath As String
    Dim i As Long
    Dim w As Variant

    Set xlApp = New Excel.Application
    Set wb = xlApp.workbooks.Add
    Set sh = wb.Sheets("Sheet1")

    fPath = CreateObject("WScript.Shell").SpecialFolders("DeskTop") & "\Test\"

    fName = Dir(fPath & "*.pdf")

    Do While fName <> ""
        i = i + 1
        sh.Cells(i, "A").Value = fName
        fName = Dir()
    Loop

    w = WorksheetFunction.Transpose(sh.Range("A1", sh.Range("A" & sh.Rows.Count).End(xlUp)))

    wb.Close False
    xlApp.Quit

    Set xlApp = Nothing

    If IsArray(w) Then
        MsgBox Join(w, vbLf)
    Else
        MsgBox w
    End If

End Sub

(β) 2015/03/22(日) 16:47


確かに表示されました。
Microsoft Excel x.x Object Linrary は参照設定をしないとだめなのでしょうか?
CreateObject関数でExcelを参照したらMicrosoft Excel x.x Object Linraryを参照しなくて済むのでしょうか?
(スズメ) 2015/03/22(日) 17:00

そんなことありまあせん。
少なくとも、最初のコードは参照設定は不要です。
エラーは別原因です。こちらでは動いていますので。

βさんのコードも参照設定不要の書き方もできないことはありません。

Sub Test2()

    Dim xlApp As Object
    Dim wb As Object
    Dim sh As Object
    Dim fName As String
    Dim fPath As String
    Dim i As Long
    Dim w As Variant
    Const xlUp = -4162

    Set xlApp = CreateObject("Excel.Application")
    Set wb = xlApp.workbooks.Add
    Set sh = wb.Sheets("Sheet1")

    fPath = CreateObject("WScript.Shell").SpecialFolders("DeskTop") & "\Test\"

    fName = Dir(fPath & "*.pdf")

    Do While fName <> ""
        i = i + 1
        sh.Cells(i, "A").Value = fName
        fName = Dir()
    Loop

    w = xlApp.WorksheetFunction.Transpose(sh.Range("A1", sh.Range("A" & sh.Rows.Count).End(xlUp)))

    wb.Close False
    xlApp.Quit

    Set xlApp = Nothing

    If IsArray(w) Then
        MsgBox Join(w, vbLf)
    Else
        MsgBox w
    End If

End Sub

(マナ) 2015/03/22(日) 17:25


マナさんのやり方でもうまくいきました。
私のコードに問題があるようです。
Set ex = nothing以降もエクセルファイルが存在するので、エクセルファイルを閉じないことが原因でしょうか?それとも、Set book = ex.Workbooks.Addかbook.Cells(c, 1).Value = bのオブジェクトに問題があるのでしょうか?

試しに、book.Cells(c, 1).Value = bを、ex.book.Cells(c, 1).Value = bにしたのですが、やはり何も変わりませんでした。この時、Option Explicitは出ていたので、エラーはありません。
(スズメ) 2015/03/22(日) 17:56


もう一度修正しました。

Sub Macro2()
Dim b As String
Dim c As Long
Dim ex As Object
Dim book As Object

    Const d As String = "C:\Users\Documents\aba\"
    Set ex = CreateObject("Excel.Application")
    ex.Visible = True
    Set book = ex.Workbooks.Add
    Set books = book.Sheets("Sheet1")
    b = Dir(d & "*.pdf")
    c = 0
    Do While b <> ""
        c = c + 1
        books.Cells(c, 1).Value = b
        b = Dir()
    Loop
    Set ex = Nothing
End Sub

エラーはなくなりましたが、うまくいきません。
(スズメ) 2015/03/22(日) 18:09


 お遊びで。
 Sub test()
    Dim fPath
    With CreateObject("WScript.Shell")
        fPath = .SpecialFolders("DeskTop") & "\Test\*.pdf"
        MsgBox .Exec("cmd /C dir /O:N /B """ & fPath & """").StdOut.ReadAll()
    End With
 End Sub
(Mook) 2015/03/22(日) 18:18

ステップ実行で確認してみてはどうでしょうか。
(マナ) 2015/03/22(日) 18:51

 参照設定

 なくても、もちろんできますが、「エクセル関連の変数記述には、やはり わかりやすい記述がいいと思いましたので」
 とコメントしたように

 As Excel.Application とか As Workbook といった記述をして、変数が何なのかわかりやすくしたかったという意図です。

(β) 2015/03/22(日) 18:55


ステップ実行というものは初めて知りました。

やってみた所、いろいろなミスを修正し、解決しました。

文字修正機能が働かない環境でマクロのコードを作るのって大変なんですね。Fortranを使っていた時代を思い出します(Fortranはマクロと似ている計算用プログラム)。

みなさんありがとうございました。

最終的なコードは以下の通りです。

Sub Macro2()
Dim b As String
Dim c As Long
Dim ex As Object
Dim fname As String

    Const d As String = "C:\Users\Documents\aba\"
    Set ex = CreateObject("Excel.Application")
    ex.Visible = True
    ex.Workbooks.Add
    fname = ex.activeWorkbook.Name
    b = Dir(d & "*.pdf")
    If b = "" Then
    MsgBox 空です
    End If
    c = 0
    Do While b <> ""
        c = c + 1
        ex.Workbooks(fname).Sheets("Sheet1").Cells(c, 1).Value = b
        b = Dir()
    Loop
    Set ex = Nothing
End Sub
(スズメ) 2015/03/22(日) 19:48

 ところで、本件、ワード内でフォルダにあるPDファイルの名前を取得することが目的だとすれば
 何もエクセルを絡めることはないですね。

 Mookさんから効率の良い DIRコマンドのEXECを使った例も出ていますが、元々の DIR関数で処理すれば。

Sub Test3()

    Dim fName As String
    Dim fPath As String
    Dim i As Long
    Dim w As Variant

    fPath = CreateObject("WScript.Shell").SpecialFolders("DeskTop") & "\Test\"

    fName = Dir(fPath & "*.pdf")

    Do While fName <> ""
        If IsArray(w) Then
            ReDim Preserve w(1 To UBound(w) + 1)
        Else
            ReDim w(1 To 1)
        End If
            w(UBound(w)) = fName
        fName = Dir()
    Loop

    MsgBox Join(w, vbLf)

End Sub

(β) 2015/03/22(日) 19:56


これで終わったのかと思ったら、昇順の話を忘れていました。

やってみたのですが、うまくいきません。

先ほどのコードの続きを書きます。

Do While b <> ""

        c = c + 1
        ex.Workbooks(fname).Sheets("Sheet1").Cells(c, 1).Value = b
        b = Dir()
    Loop
の後に、

ex.Workbooks(fname).Worksheets("Sheet1").Range(ex.Workbooks(fname).Worksheets("Sheet1").Cells(1, 1), ex.Workbooks(fname).Worksheets("Sheet1").Cells(10, 1)) _

               .Sort Key1:=ex.Workbooks(fname).Worksheets("Sheet1").Cells(1, 1), order1:=xlAscending
    Set ex = Nothing
End Sub

ステップ実行すると、ex.Workbooks(fname).Worksheets("Sheet1").Range(ex.Workbooks(fname).Worksheets("Sheet1").Cells(1, 1), ex.Workbooks(fname).Worksheets("Sheet1").Cells(10, 1)) _

               .Sort Key1:=ex.Workbooks(fname).Worksheets("Sheet1").Cells(1, 1), order1:=xlAscendingの所でrangeクラスのsortメゾットに失敗しましたと出てしまいます。

さらに、こちらの方法でやると、

Do While b <> ""

        c = c + 1
        ex.Workbooks(fname).Sheets("Sheet1").Cells(c, 1).Value = b
        b = Dir()
    Loop
の後に、
ex.Workbooks(fname).Worksheets("Sheet1").Range("A1:A8").Select
    ex.Workbooks(fname).Worksheets("Sheet1").Sort.SortFields.Clear
    ex.Workbooks(fname).Worksheets("Sheet1").Sort.SortFields.Add Key:=ex.Range("A1"), _
        SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
    With ActiveWorkbook.Worksheets("Sheet1").Sort
        .SetRange ex.Workbooks(fname).Worksheets("Sheet1").Range("A1:A8")
        .Header = xlNo
        .MatchCase = False
        .Orientation = xlTopToBottom
        .SortMethod = xlPinYin
        .Apply
    End With

の、
ex.Workbooks(fname).Worksheets("Sheet1").Sort.SortFields.Add Key:=ex.Range("A1"), _

        SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
のところで、アプリケーションまたはオブジェクト定義のエラーですと出てしまいます。

よろしくお願いします。
(スズメ) 2015/03/22(日) 20:19


 >昇順の話を忘れていました。 

 そちらのコードを無視しているようで申し訳ありませんが、エクセルを絡める必要がないので

 Sub Test4()

    Dim fName As String
    Dim fPath As String
    Dim i As Long
    Dim w As Variant
    Dim sl As Object

    Set sl = CreateObject("System.Collections.SortedList")

    fPath = CreateObject("WScript.Shell").SpecialFolders("DeskTop") & "\Test\"

    fName = Dir(fPath & "*.pdf")

    Do While fName <> ""
        sl(fName) = True
        fName = Dir()
    Loop

    ReDim w(0 To sl.Count - 1)

    For i = 0 To sl.Count - 1
        w(i) = sl.getkey(i)
    Next

    MsgBox Join(w, vbLf)

 End Sub

(β) 2015/03/22(日) 20:28


 今のところ、Excelを何故使用するかわからないのは確かなのですが、

 それよりも大切なこと。
 繰り返しになりますが、まずは、Option Explicitです。
 忘れてませんか。

(マナ ) 2015/03/22(日) 20:45


 マナさんのコメント実践した方が良いですよ。
 Option Explicit

    MsgBox 空です
 が意図しないものであることがすぐにわかったはずですから。

 それから蛇足ですが、FORTRAN に限らず、ほとんどのプログラミング言語でもインデント
 のルールは共通なので、もうすこしきちんとインデントを付けた方が良いと思います。
 Python などインデント自体にも意味があるので、誤ったインデントだと動きません。

(Mook) 2015/03/22(日) 20:51


βさん、
ありがとうございます。

私がExcelをわざわざ使ったのは、昇順の機能がエクセルにしかないと思ったからです。

まさか他の手段があるとは思いませんでした。
早速βさんのコードを試してみます。

マナさん、
アドバイスありがとうございます。
これからはOption Explicitをつけていこうと思います。ただ、なぜOption Explicitは大事なのでしょうか?

Mookさん、
アドバイスありがとうございます。
これからはインテンドを挿入していこうと思います。

(スズメ) 2015/03/22(日) 21:08


 >ただ、なぜOption Explicitは大事なのでしょうか? 

 Mookさんご指摘の部分に気づいていましたか。
 また今回のエラーの原因にも、実行する前に気がついたはずですよ。

 Excelを使う必要がないことが確定のようなので、気になったことを最後に。

 >fname = ex.activeWorkbook.Name
 >ex.Workbooks(fname).Sheets("Sheet1").Cells(c, 1).Value = b
 これは、fname 使わなくても
 ex.activesheet.Cells(c, 1).Value = b
  でよいです。
 ただ、後でソートするコードを書くのならば、
 βさんのコードのようにシートを変数にsetしておくほうがよいと思います。

(マナ ) 2015/03/22(日) 21:34


 >なぜOption Explicitは大事なのでしょうか? 

 以下のコードを Option Explicit を記述せずに実行してください。
 で、次に Option Explicit を記述して実行を試みてください。

 Sub TestNG()
    actreceivable = 1000
    actreceived = 800

    MsgBox "売掛金残高は " & accreceivable - actreceived & "です"

 End Sub

(β) 2015/03/22(日) 22:01


Sub TestNG()
    actreceivable = 1000
    actreceived = 800
    MsgBox "売掛金残高は " & accreceivable - actreceived & "です"
End Sub

そういうことだったんですね。

特にCreateObjectの時には大事なんだとわかりました。

説明ありがとうございました。

あと、みなさんどうもありがとうございました。
(スズメ) 2015/03/22(日) 22:13


 >そういうことだったんですね

 と、言っていただきましたけど、きわめて悪い例でした。(汗)
 理解いただきたかったことを正しくコードに書き直しました。

 Sub TestNG()
    Dim actreceivable As Long
    Dim actreceived As Long

    actreceivable = 1000
    actreceived = 800

    MsgBox "売掛金残高は " & accreceivable - actreceived & "です"

 End Sub

(β) 2015/03/22(日) 22:32


返信遅くなってすいません。

スペルミスの発見のためというのはわかりましたので大丈夫です。

どうもありがとうございました。
(スズメ) 2015/03/24(火) 16:40


 スペルミスの発見だけでは、ちょっと足りないと思います。
 この2対、Option Explicit宣言しないで実行してみてください。 結果が異なるはずです。

    Sub OE1()
        Dim d As Date
        d = "2015/1/1"
        Debug.Print d + 1
    End Sub
    Sub OE2()
        d = "2015/1/1"
        Debug.Print d + 1
    End Sub

    Sub OE3()
        Dim a As String, b As String
        a = 1
        b = 0
        Debug.Print a + b
    End Sub
    Sub OE4()
        a = 1
        b = 0
        Debug.Print a + b
    End Sub
 型宣言しないということは、意図しない動作が出たときに、発見しにくいので
 型宣言を強制するのは大切なことだと思います。
(稲葉) 2015/03/24(火) 18:33

返信遅くなりすいません。最近は忙しいもので。

sub OE2()は型が一致しませんとでて、結果が出ませんでした。

でも、OE1とOE2の所で稲葉さんが何を言いたいのかはわかった気がします。おそらく以下のマクロと同じような感じじゃないかと思います。

この場面でしたら遭遇したことがあります。そのコードを書いておきます。2行目と8行目に日付が書いてあって、条件付き書式のマクロをDoループで実行します。週末の部分に色を塗るためです。

Sub Macro1()
Dim a As Integer
Dim b As Integer
Dim atc As String
a = 2
b = 2
Do Until a = 20
Do Until b = 9
Cells(a, b).Select
atc = Cells(a, b).Address(ReferenceStyle:=xlR1C1)

    Selection.FormatConditions.Add Type:=xlExpression, Formula1:= _
        "=WEEKDAY(" & atc & ")=7"
    Selection.FormatConditions(Selection.FormatConditions.Count).SetFirstPriority
    With Selection.FormatConditions(1).Font
        .Color = -1003520
        .TintAndShade = 0
    End With
    Selection.FormatConditions(1).StopIfTrue = False
    Selection.FormatConditions.Add Type:=xlExpression, Formula1:= _
        "=WEEKDAY(" & atc & ")=1"
    Selection.FormatConditions(Selection.FormatConditions.Count).SetFirstPriority
    With Selection.FormatConditions(1).Font
        .Color = -16776961
        .TintAndShade = 0
    End With
    Selection.FormatConditions(1).StopIfTrue = False
    b = b + 1
    Loop
    b = 2
    a = a + 6
    Loop
End Sub

これは正しく実行できるマクロですが、昔はatcの部分をCells(a,b).valueまたは、Cells(a,b)と書いていました。そうすると、例えばCells(a,b)の部分が2015/1/1と書いてあるとすると、2015÷1÷1と誤って認識されてしまうんですよね。そうすると、土曜日や日曜日になっても色が塗られないんですよね。
(スズメ) 2015/03/26(木) 23:05


 OE2はエラーが出ることが分かっていただければ結構です。
 日付型 + 1 は計算できるけど
 文字列 + 1 は計算できないということです。

 読む気にならないコードですね。
 それと全然わかってないようですね。
 変数がString型でも、""は自動では付きません。

 × Weekday(2015/1/1)
 ○ Weekday("2015/1/1")

 FormatConditionsの引数は、String型で求められているので
 "=WEEKDAY(""" & Cells(a , b).Value & """)=7"
 ならできるんじゃないですか?

 それにセルひとつひとつに異なる条件付き書式設定したら、再計算で重くなるでしょう?
 どうせマクロ使うなら、色つけちゃえばいいのに。

(稲葉) 2015/03/27(金) 08:49


 稲葉さんから指摘の「型宣言の重要性」というのは、以下のようなことかと。
 たとえば 型宣言をしないコードだとすると。

 Sub SampleNG()
    '
    'いろんな分岐がある膨大で複雑なコードで
    '
    num = Range("A1").Value
    '
    '
    '別の場所で
    num = 2
    '
    '
    '
    '別の場所で
    num = 別の変数A
    '
    '
    '
    'またまた別の場所で
    num = 別の変数B
    '
    '
    '
    '最終的に
    結果 = num * 100

 End Sub

 こういったものがあったとして、最終的に、結果 = num * 100 を実行しようとして「型が違います」というエラーになった。
 調べると、変数 num に数値ではないものが入っていた。

 どうしますかね。膨大で複雑なコードのあちこちで、変数numに値を代入しているところを、かたっぱしから調べて
 ここはいいよなぁ、じゃぁ、あの条件の時のここはどうかなぁ・・・・と、「犯人捜し」をしますよね。

 言ってみると、事件が発生して、犯人も逃亡した後に、捜査するわけです。

 ところが、このプロシジャで、 Dim num As Long と規定しておけば、事件が発生する前、num に数値以外が代入されたところで
 「型が違います」というエラーになります。

 つまり、犯人が逃亡する前に、ピンポイントで「現行犯逮捕」ができるわけです。

 これは、開発生産性が格段にアップする要素ですよ。

 別スレで(スズメ)さんが、
「バグがあってループした際に、制御をLong型でやると戻ってこないで激しく固まる。Integer型だとわりあいすぐにもどるので開発生産性で有利」
 というような(これはこれで、ん?? ですけど)コメントをしておられましたが、そこまで気を配るなら(?)
 変数型宣言は【必須】アイテムでしょうね。

(β) 2015/03/27(金) 09:10


このコードはだいぶ前に作ったものなのでインテンドが入っていません。すいません。

わざわざセルのアドレスを求めなくても別の方法があるとは思いませんでした。

変数の宣言の意味は皆様のおかげでわかりました。今まで、何の為にやるのだろう?変数を宣言しなくても動くのにと思いながらも変数の宣言をしていました。過去にFortran(マクロと似ている計算用プログラム)の授業を受けたことがありまして、その頃は先生に動的配列を除いて変数の宣言をしろと言われなかったもので。マクロでも同じなのかなと思っていました。

ただ、文字列のほうでまだ引っかかることがあります。
これ以上ここで質問を続けるとタイトルと異なった内容になってしまうので、新しく別の場所を設けて質問をしたいと思います。

(スズメ) 2015/03/27(金) 14:37


 単なる雑談だが。

 COBOLをやってると変数の宣言が当たり前になる。
(ねむねむ) 2015/03/27(金) 14:42

余談ながら、Fortranだって、7だろうが77だろうが、変数宣言は必須でした。最近は省略できるのですか?

VBAは、Basic言語の流れを汲んでいるので、変数宣言を省略することができます。
そのせいで、変数名等を打ち間違っても、別変数として扱われてしまい、エラーにならないのです。

Option Explicit宣言すると、変数宣言省略を許さずに、エラー指摘してくれるようになります。
ネットで打ち間違いのつまらない問題を晒すのは恥ですよ。少なくとも、Fortranに触っていたくらいのプロレベルの人が、絶対やってはならないミスです。

なお、Option Explicitはいちいち手入力するのではなく、VBA編集画面のオプションで、「自動構文チェック」すると良いです。
デフォルトでチェックが付いてても良いくらいだと思うのですけどねぇ。Microsoftは、省略できることをデフォルトにしていますね。
(???) 2015/03/27(金) 15:30


 余談の脱線ですみません。
 どの版からは不明ですが Fortran は変数宣言の省略が可能のようです。
 VBA のように、変数宣言を強制する構文として、implicit none があるようです。
http://www.nag-j.co.jp/fortran/FI_17.html#ImplicitTyping

 もちろん、本論において Option Explicit を使いましょう。
 という点に変わりはありませんが。
(Mook) 2015/03/27(金) 16:05

そういえば、I〜Nで始まる変数は整数型、ってルールがありましたね。忘れてました。勘違いです。
IMPLICIT INTEGER A-Zとかすれば、全ての変数が整数型になって、配列以外は宣言不要でした。
単に、私が必ず変数宣言していただけですね。ってことは、以前から打ち間違いによるバグがあったんだ…。
(???) 2015/03/27(金) 16:27

こんにちは。堅苦しいことを言うようで恐縮です。

整数を格納する変数の型ですが、本来は、数値の大きさに応じてInteger型なりLong型なり
使い分けるのが正しいあり方だと思います。理由は、まさにβさんがおっしゃっているように
異常な値がはいったときにできるだけ早い段階でみつけるためです。

わたし自身は、ExcelVBAに限り整数はすべてLong型と割り切っていますが
教科書的に原理原則を言うなら「数値の大きさに応じて使い分けるべき」です。

( 佳 ) 2015/03/27(金) 18:52


 >教科書的に原理原則を言うなら「数値の大きさに応じて使い分けるべき」です。 

 昔のメモリやディスクが狭い環境であれば、必要十分なサイズを使用することに
 意味があったと思います。
 それでも当時初期の設計では Int(16bit) で十分だろうと思っていたものが、
 使い始めたら足りなかったということは多々ありました。
 現在でも組込型のプログラムなど、メモリが限られた環境では必要な配慮かと思います。

 >異常な値がはいったときにできるだけ早い段階でみつけるためです。 
 同じ整数型の中の話ではなく、整数型と文字列型といった、明らかに異なるデータタイプ
 に関することではないでしょうか。

 整数だけに限れば、PCの素人プログラミングであれば、十分なデータ設計など期待する
 べくも無く、 整数の最大が扱えるデータ型(VBA なら Long)としておくのが、
 妥当な気がします。

 日付データの 2000 年問題を知っている人はもはや少ないかもしれませんが、
 世界中に使用されていた日付データですら、十分ではなかったのはよい教訓でしょう。
 2038年問題までには、64bit(128bit?)データが標準になっていると思いますので
 顕在化はしないでしょうけれど。
(Mook) 2015/03/27(金) 19:16

別の所でも言いましたが、Integerにしておくとまれに役に立つことがあります。
Integerにしておけば、もし誤って無限ループを作ってしまったときに、ある変数が32768?を越えたときに止まってくれます。おそらく佳さんはこれを言いたいんだと思います。

あと、fortranはプロでなくてもできると思います。
むしろ、vbaの方が、ファイルのダウンロードとか、ファイルの印刷になってくるとfortranよりも難しいですし、fortranはこれはできません。
(スズメ) 2015/03/27(金) 19:34


 >別の所でも言いましたが、Integerにしておくとまれに役に立つことがあります。 
 は拝見しましたが、一般に納得される理由ではありませんので、あまり声高に
 主張されないほうが良いように感じます。

 デバッグ時の利便性(?)より、リリース後に長期間安定して動くことの方が遥かに重要な要件でしょう。
 デバッグで100や200のデータで試して問題なかったけれど、実際は10万のデータがあって、
 エラーが出たという方がまずくは無いですか?

 FORTRAN vs VBA 論は
 紛糾するだけの気がしますので、やめておきます。
(Mook) 2015/03/27(金) 20:13

 >Integerにしておけば、もし誤って無限ループを作ってしまったときに、ある変数が32768?を越えたときに止まってくれます。おそらく佳さんはこれを言いたいんだと思います。 

 佳さんにお聞きしなければわからないことですが、おそらく、そういうことを言っておられるのではなく
 その数値が扱うものが、絶対に Integer型の範囲のものなら、原理原則として As Integer が妥当だろうと
 そういうことだと思いますよ。
 でも、そういったことに頭を使うより、もっともっと、配慮すべきところは(プログラムを書くばあいに)多いでしょうね。

 無限ループの件、別スレでコメントされた際には「承っておきます」にとどめましたけど、正直、その理屈はおかしいです。
 これは【開発フェーズ】の話で、もちろん、開発生産性をあげるために、たとえば、最終的には使わない
 セルのSelect や シートの Select なんてコードを、あえて入れることがあります。
 テストをしながら自分が予期したアドレッシングがなされているかどうかを、ステップ実行等で確認するためです。

 しかしながら、このようなものは、本番前に削除します。

 VBAコードを書く人は2種類でしょうね。
 自分の業務で自分が使うために書く。IT担当として、ユーザが使うものを(開発者の立場で)書く。

 で、「学校」のようなQ/A掲示板では、これが明白で、質問者さんがユーザ、(スズメ)さんは開発者です。
 開発者が、ユーザに提供するプログラムについて、ユーザに、

 「今度のプログラムは、非常にユーザさんに配慮したものになっています。かりにバグがあってループに陥った時に
  他の人が書くプログラムは、なかなかもどってこないで、固まったようになり、貴重なユーザさんの時間を無駄にしてしまう。
  一方、私のプログラムは、結構早く、実行時エラーになって、ユーザさんの貴重な時間を無駄にすることを最低限におさえます。
  どうです。配慮がいきとどいているでしょう」

 こんなふうにいうと、ユーザーさんは、「絶句・・・・」でしょうね。

(β) 2015/03/27(金) 20:46


いろんなサイトで調べてみたのですが、integerよりlongの方が早いことに気づきました。以前βさんがlongの方がわずかに早いといっていたのですが、私は信じることができませんでした。申し訳ありません。なぜなら、integerのほうがコンパクトだからです。しかし、integerは特殊で、一旦32ビットに変換してから計算されるので、コンパクトによるメリットよりも、変換によるデメリットのほうが大きいのかもしれません。variantとlongならlongのほうがコンパクトなのでlongのほうが早いと書いてありました。

なので、私は、これからは基本的にlongで宣言していこうと思いますが、無限ループが出そうな場合とか、パソコンの空き容量がかなり少ない場合など、特殊な事情があればintegerにするつもりです。

どうも貴重な意見を下さりありがどうございました。
(スズメ) 2015/03/27(金) 22:11


 しつこいようですが。

 >無限ループが出そうな場合

 バグは本番開始前にとりさっておくことが必要なのはいうまでもありません。
 テストが完了したら As Long に書き直しておかれたらいいと思います。
 また、バグ ではなく、何らかのプログラム以外の要因でループしてしまうということは、ありえます。
 この場合も、それを取り除く、あるいは、どうしても取り除くことができない場合は、ループ回数の制限を
 ロジックに組み込むべきでしょうね。(そこまでやるかどうかは、疑問ですが。)

 >パソコンの空き容量がかなり少ない場合

 1960年代終わりの、電子計算機が技術者の研究室から、ようやくエンタープライズといいましょうか
 商用コンピュータとして世の中に出始めたころならわかりますが、昨今のPCの環境で変数をLong型で持つ、そのプログラムサイズと
 Integer型でもつサイズの差は【電子顕微鏡】でのぞかなければわからないくらいの差でしょう。

(β) 2015/03/27(金) 22:32


 失礼ながら、スズメさんって突っ込まれ体質?

 あれだけの短い文章なのに、
    ■なぜなら、integerのほうがコンパクトだからです。
    ■しかし、integerは特殊で、・・・変換によるデメリットのほうが大きいのかもしれません。
    ■コンパクトなのでlongのほうが早いと書いてありました。
    ■無限ループが出そうな場合とか、
    ■パソコンの空き容量がかなり少ない場合など、
 と、「えーーーっ、それはどうかな・・・」と感じる表現が一面に。 

 どうも物事を一面だけでとらえているような印象を受けてしまいました。
 いろいろと批判ばかりのようで、ごめんなさい。
 これで終わりにします。

 なんだかんだ言いましたが、インデントにしても型宣言にしても、
 人の意見を受け入れる行動は素晴らしいと思います。

 論争で終わってしまう人も、これまた大勢いますから。
(Mook) 2015/03/27(金) 23:43

 私も、これで終わりにしますが、1つエピソードを。

 別の板ですが、2年ほど前だったか、ある回答者さんがデビューされました。
 大変積極的で、また前向き志向の方でした。ちょうど、VBAを覚えられ、コードを書くのが楽しくて楽しくて
 といった印象でした。

 ただ、その人がアップする回答コードが、例の

 シート.Select
 セル.Select
 Selection.なんたら

 このオンパレードでした。

 極端な例としては

 Range("A1").Select
 Selection.Value = "ABC"

 他の皆さんが再三再四、その点について、その弊害も含めてアドバイスをされたんですが、全く聞く耳を持たず

 ・自分は、マクロ記録しか見ていない。マクロ記録ではこうなっている。
 ・ちゃんと動くんだからいいだろ。
 ・何より、この書き方が一番わかりやすい。何かを選択して、その選択したものに何かをする 理路整然としたものになっている。
 ・自分がわかりやすいということは、質問者にとってもわかりやすいはずだ。

 で、それから2年ほどたったわけですが、現在の、その回答者さんがアップする回答コードは
 いわゆる通常の(当初のコードと比較すれば、見事というか美しい)コードになっています。

 まぁ、(スズメ)さんも、いずれ、コードの強度や開発生産性といったものを、肌でかんじていかれるうちに、
 また違った考えをもたれるようになるかもです。

(β) 2015/03/28(土) 08:18


こんにちは。出遅れました。
いまさらではありますが、少々。

わたしが言っているのは原理原則です。
異常値を発見する役に立つものはできる限り使う。
たとえ整数であってもです。
コード作成時、検証時のエラーは出れば出るほどよろしい、と
わたしは考えています。

実務のはなしはべつです。
エクセルの実務では、整数については「今日の異常値は明日の正常値」ということが
よくあります。安全率を大きくとれば、Long型にならざるをえません。
とはいえ、「ならざるをえません」は「ぜひそうあるべき」とは違います。

to スズメさん
こんな風に言っては失礼かもしれませんが、感心しました。
32ビット環境でLong型のほうが速い理由を自分で探しだしてこられた方を、
わたしは初めて見ました。すばらしいです。

ですが、どのくらい速いかも重要ではないでしょうか。
βさんは「顕微鏡的」とおっしゃっています。
わたしも少し前に計測してみましたが、for nextのループを使って3億回ループさせて
処理にかかった時間の差は2秒でした。ループ1回あたり1億5000万分の1秒です。
(3億回もまわした理由は3000万回では「誤差」なのか「差」なのか判断がつかな
かったので、一桁上げてみました。)

ついでに、環境があったので、64ビット環境でも計測してみましたら、
結果は逆転しました。3億回のループでInteger型が1秒速かったです。

いずれにしても微々たる差です。人間に感知できるほどの違いはありません。
どちらを選ぶにしても、スピードを理由に選ぶのはナンセンスです。

スズメさんならきっと、もっとちゃんとした理由を見つけられると思います。
ぜひ見つけて欲しいと思います。(なんだかえらそうですね、すみません)

( 佳 ) 2015/03/31(火) 20:09


コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.