こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

VBAにおける文字列結合と繰り返し入力の組み合わせについて

はじめまして,VBA初心者ですがよろしくお願いいたします。
今,データベースから文字列を抜き出してセルに等間隔で貼り付けるというプログラムを作成しています。
実際は,もっと複雑なプログラムなのですが質問のために簡単にしました。

Sub 例文()
For a = 1 To 10001
ggx = あるデータベース
Dim i As Integer
For i = 1 To 13
文字列 As String
文字列 = 文字列 & MidB(ggx, i * 80 + 95, 2)
Next i
.Cells(2 * a + 4, 1).Value = 文字列
Next a
End Sub


この式だと,セルに返したときに一番最初のセルには要求した文字列が
貼り付けられるのですが,次以降のセルには,要求した文字列に加えて前のセルの文字列も返されてしまい最終セルには,膨大な文字列が返されてしました。

ちなみに,詳しく書けなくて申し訳ないのですが変数aによってデータベースの内容は変化します。
MidB(ggx, i * 80 + 95, 2)
という関数でデータベースから条件に当てはまるいくつかの文字列を抜き出してセルに返すことまでは出来たのですが返し方がうまくいきません。

質問の仕方が下手で非常に申し訳ないのですがどうぞアドバイスをお願いします。

投稿日時 - 2008-04-12 00:11:50

QNo.3941538

すぐに回答ほしいです

質問者が選んだベストアンサー

多分こんな感じでいいんではないでしょうか?
基本的には「For a = 1 To 10001」の後で「For i = 1 To 13」の前で初期化してやる必要があると思います。
(.Cells(2 * a + 4, 1).Value = 文字列 のためのデータを取得し始める前に初期化する)
それと、確かにANo.5さんの指摘通り、Midbで取得したままcellに代入していると、量はともかく正しい値が表示されているのでしょうか・・・

Sub 例文()
For a = 1 To 10001
dim 文字列 As String'この上でもいいけど
文字列=""
ggx = あるデータベース
Dim i As Integer
For i = 1 To 13
文字列 = 文字列 & MidB(ggx, i * 80 + 95, 2)
Next i
.Cells(2 * a + 4, 1).Value = 文字列
Next a
End Sub

投稿日時 - 2008-04-12 19:43:36

お礼

返事が遅くなり申し訳ありませんでした。アドバイスの通りやってみたら,見事に要求どおりに動いてくれました。ありがとうございました!!!
「文字列=""」はここに質問する前,試行錯誤やっている途中に,入力したことはあるのですが,「For i = To 13」の後に入力してしまい,要求どおりの効果を得られなかった記憶はあります。変数の属性決定のタイミングにより効果が違ってくるとは,VBAは奥が深いです・・・・

投稿日時 - 2008-04-14 21:16:18

このQ&Aは役に立ちましたか?

7人が「このQ&Aが役に立った」と投票しています

回答(8)

ANo.7

#5です。
スルーしようかとも思ったのですが、
#6の回答は、ホントに#5(vizzar)へのものなんでしょうか。

私は、
1.「文字列 As String」は変数の初期化を意図して置いたものだと理解した
2.ならば、「初期化が効いていないと判断」できないのかな
と思っただけでして。。。

投稿日時 - 2008-04-12 19:19:55

 回答者どうしのやりとりは禁止されているので、これ一回にします。

 #5さんへ。だから、VBAの仕様がどうなってるかなんです。VB.Net(2002以降)では、質問者様のコードでも、ちゃんとした結果が出ます。ところがMSは、VBAはVBのサブセットだと言い切っているにも関わらず、現在の実態は、.Net以前のVB6仕様に現在のVBAは準拠しています。これは「VBA初心者」という事を考えれば、気づける範囲のものではありません。
 現在のMSは「VBAはVBのサブセットだとは一言も述べていない」なんてのは、理由にならないと思います。そうであるならば、「MSは、ちゃんとそう言うべきです」。これは未必の故意と同じです。

 以上、個人的意見です。

投稿日時 - 2008-04-12 18:28:38

ANo.5

データベースの文字列は全てANKなのでしょうか?
2バイトコードがあるとMidB関数はヤバイですね。
因みに、「日本語」という文字列は、Mid関数では3文字です。
ANKの「ABC」もMid関数では3文字です。
つまり、Mid関数はバイト数でなく文字数で働きます。

本題のほうですが、
> 次以降のセルには,要求した文字列に加えて前のセルの文字列も返されてしまい
これを読んだ途端に「あ、初期化されていないな」と直ぐに感じました。
だとすると「文字列 As String」が効いていないと類推出来るハズなんですが...

投稿日時 - 2008-04-12 18:01:15

 #3さんの回答に大きなお世話です。たぶん質問者様は、VBAのほかに、.Net以降のVBも知っていらっしゃるのではないかと思います。
 VBAはVBの完全なサブセット(機能限定版)というのがMSの公式見解ですが、現在は違います。
 現在のVBAは、VB6のサブセット(.Net以前)です。#3さんも仰っているように、VB6のローカル宣言 Dim は、どこに書いても、プロシージャ内で一回きりの宣言となります。これに対して .Netでは、If や For Loop 内のブロック内ローカル宣言がサポートされています。

投稿日時 - 2008-04-12 10:21:43

質問内の「文字列 As String」は「Dim 文字列 As String」のつもりだと思って話をします。

スコープ内でローカルな変数を使おうと宣言しているつもりでも・・・
VBAは期待している事をしてくれません。

こんな感じ
Sub test()
Dim i As Integer
For i = 1 To 5
Dim 文字列 As String'<-文字列=""の初期化も期待してるんだけど
If i = 2 Then
文字列 = "ABC"
End If
MsgBox 文字列
Next
End Sub
明示的に初期化すればいいだけの話なんですが、以降で初期化されてなければエラーを出して欲しい(チェックして欲しい)。

恐ろしいのは、これでエラーが出ない所です。
Sub test()
Dim i As Integer
For i = 1 To 5
Dim 文字列 As String
文字列 = "ABC"
Next
MsgBox 文字列
End Sub

本当に困ってしまうのは、こんな場合なんですよね。
ちょっとスコープ内でローカルな変数使いたいだけなんだけど・・・
Sub test()
Dim i As Integer
For i = 1 To 5
Dim 文字列 As String
文字列 = "ABC"
Next
For i = 1 To 5
Dim 文字列 As String '<-ここでエラーになる
文字列 = "DEF"
Next
End Sub

多分dimはどこにあってもプロシージャ内で先頭に(上の例でのDim i As Integerと同じ位置に)あるとするみたいです。
と言うわけで、「言語の仕様」ですので、そういう時は
Dim 文字列 As String
文字列=""
としましょう。
せめて
Dim 文字列 As String = ""
を許してくれると助かるんですが・・・

投稿日時 - 2008-04-12 04:38:56

お礼

>質問内の「文字列 As String」は「Dim 文字列 As String」のつもりだと思って話をします。
私の入力誤りを見越してのご回答ありがとうございました。今回は非常にわかりやすい説明ありがとうございました。

投稿日時 - 2008-04-14 21:18:47

ANo.2

質問をあまり理解できていませんし、
VBAから近年遠ざかっていますが、
なんとなく、こんな感じかな と思って書いてみます。

ループ内で文字列を一度初期化する必要があると思います。
(以下では、s = "" としました)

Sub 例文()
Dim ggx As String
Dim s As String
Dim a As Long
Dim i As Long
For a = 1 To 10001
ggx = "なにか文字列"
s = ""
For i = 1 To 13
s = s & MidB(ggx, i * 80 + 95, 2)
Next i
.Cells(2 * a + 4, 1).Value = s
Next a
End Sub

投稿日時 - 2008-04-12 01:42:50

ANo.1

書かれてある通りの動作をしているとしか思えないのですが。
つなげたくないならつなげないようにすればよいかと思います。
文字列 = MidB(ggx, i * 80 + 95, 2)
ひょっとして的外れなんですかね?

投稿日時 - 2008-04-12 01:27:03