- ベストアンサー
Excel2003でstring型のデータの所定文字数の数を取得する方法
- Excel2003のVBA関数を使用して、string型のデータで特定の文字の出現回数を取得する方法について質問があります。例えば、特定の文字列内に存在するカンマの数を取得する方法を知りたいです。2次元配列要素を1次元で一時格納し、それを再度2次元に格納する際にカンマの数を数える必要があるため、処理をスムーズに行いたいです。
- 例えば、string型のデータがmyDataに格納されています。このデータ内のカンマの数を取得したいとします。
- 質問者は、データが変更されるたびにカンマの数を数えて配列を再宣言するのが面倒であり、どれだけの数のカンマがあっても2次元に再格納できるようにしたいと考えています。具体的な方法を教えてください。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
こんばんは。 >dim mydata(20000, 10) as Variant >と言う形等で、配列数を多く宣言しておけばいいのでしょうが、 >このやり方って空のデーターの箱を沢山作ってしまいっているので >なんかもったいないなと思って動的配列で宣言しております。 私は、他の言語を勉強したときに、なぜ、VBAやVBでは、そういう仕方をしないのかなって思ったことがあります。たぶん、根本的に、VBAやVB は、速度が遅いのが原因ではないか、と思います。それに、Ubound で上限が取れないので、配列の代入時に、カウントして、それを元にする、というしかないわけです。 >Find関数を用いて、条件を満たした行の必要な列をカンマで結合して格納してく方法を用いてます。 似たようにことを、私も以前やったような覚えがあります。 動的な2次元配列が、VBAの上級文法の最後のひとつに入りますね。上級とはいっても、必要不可欠です。 Excelでは、有名な「バブルソート・アルゴリズム」をExcelシートに応用するという命題みたいなものがあります。一応、掲示板の常連さんは、みなさん、一度は勉強していると思います。(偉そうな言い方で申し訳ないのですが。) とはいえ、なぜ、Excelにとって、2次元配列がややこしいかというと、お気づきだと思いますが、排出の仕方が、縦横逆になるからなのです。For Each ~ in myRange でやってみると、左から右へと動いていくのが分かりますが、配列は、添え字の1次側から順に排出てしていきます。ちょっと不思議ですよね。たぶん、これは、メモリの確保の仕方から来るものだと思います。 また、2次元の場合は、二次側を、動的配列にします。一次側は固定されます。 Redim Preserve myData(固定値, カウンター) それから、 WorksheetFunction.Transpose これは、1次元に限ります。ただ、こういうレベルというのは、このサンプルで見たとおり、そのままですから、 Worksheets("Sheet2").Range("A1"). _ Resize(UBound(myData, 1) + 1, UBound(myData, 2) + 1).Value = myData() で、形どおりに貼り付けが可能です。 ----------------------------------------------------------- 先ほどからずっと、動的2次元配列のサンプルが思いつきませんので、#1さんの補足に書かれたものを元に書いてみました。一般的には、配列に配列を入れるようなことはしないで、そのまま、1行ずつ排出します。 なお、余計なことかもしれませんが、私個人は、 Option Base 1 を使わないことにしています。将来的になくなるということもありますが、今回のコードの場合は、逆にややこしくなっているようです。配列は、0からスタートと考えていたほうが安全です。 ためしに、入れ替えてみました。以下のコードのように、Max で、上限を取らざるを得ません。それ以外に、列幅の上限を知る方法はありません。通常は、一行ずつ処理するというのが一般的です。ここまですると、ややこしいです。 'Option Explicit Option Base 1 Sub ArrayTest() Dim buf As Variant Dim Max As Integer Dim i As Long Dim j As Long Dim k As Long Dim v As Variant Dim myData(10) Dim myAray() As Variant Dim OutPutData() As Variant myData(1) = "あ,い,う,え,お" 'ここの列数は不明ゆえ myData(2) = "か,き,く,け,こ" 'Max を取る myData(3) = "さ,し,す,せ,そ" myData(4) = "た,ち,つ,て,と" For i = 1 To UBound(myData) If myData(i) = Empty Then Exit For buf = Split(myData(i), ",") ReDim Preserve myAray(1, i) '動的2次元配列 '配列をチェックしないと、エラーが出る If IsArray(buf) Then If (UBound(buf) + 1) > Max Then Max = (UBound(buf) + 1) End If myAray(1, i) = buf Next i ReDim OutPutData(i - 1, Max) For j = 1 To i - 1 For Each v In myAray(1, j) k = k + 1 OutPutData(j, k) = v Next v k = 0 Next j Range("A1").Resize(UBound(OutPutData(), 1), UBound(OutPutData(), 2)).Value _ = OutPutData() End Sub 何かのヒントになった幸いです。
その他の回答 (2)
- Wendy02
- ベストアンサー率57% (3570/6232)
こんばんは。 言葉で説明されても、私は、あまり理解力がないせいか良く分からないですね。 私自身は、本来は、全体的なものを見て判断したいですね。 2次元配列と1次元配列を行き来するということは、通常はしません。モーグの有名な方は、そういうテクニックを公開していますが、まず、私は、そういうことには直面しません。 通常は、2次元は、最初から、2次元のまま処理するのが普通だと思います。 ただし、CSVなどは、1次元で行ごとに処理します。 String型で入手したものは、 Dim myStr As String Dim i As Long Dim j As Long myStr = "a,b,c,d,e" i = Len(myStr) - Len(Replace(myStr, ",", "")) j = UBound(Split(myStr, ",")) このどちらかになりますが、状況によっては、「i」側は、区切り文字が、TextCompare が選べる利点があります。なお、正規表現は、私は、この種類には使いません。理由は、遅いからです。
お礼
お返事ありがとうございます。 Len関数とreplace関数でこのような形で得られるのですね。 それと、jの取得の仕方。まるっきり気がつきませんでした。 ありがとうございます。 余談なのですが) <<通常は、2次元は、最初から、2次元のまま処理するのが普通だと思います。 2次元で格納していくスキルが無いため、無理やり1次元で仮格納して 2次元にしてセルに書き出すやり方をしております。 Find関数を用いて、条件を満たした行の必要な列をカンマで結合して 格納してく方法を用いてます。 最初に dim mydata(20000, 10) as Variant と言う形等で、配列数を多く宣言しておけばいいのでしょうが、 このやり方って空のデーターの箱を沢山作ってしまいっているので なんかもったいないなと思って動的配列で宣言しております。 そうすると、どうしてもRedim Preserveで1次元目を宣言しなおせ ないので1次元で必要な列データをカンマで結合して格納していって いるしだいです。 書き出しの時に WorksheetFunction.Transpose を上手く使えば2次元の要素を増やしていく格納のやり方とか 出来そうな気がするのですが、自分の頭の中が混乱してくるのと Transposeの使い方が理解できていないため、 2次元で格納→2次元で書き出し を行わず 1次元で格納→2次元で書き出し と言う処理にしております。 余談終了) wendy02様にはいつもご丁寧なアドバイス、ご回答をいただき誠に ありがとうございます。
- hana-hana3
- ベストアンサー率31% (4940/15541)
Split()関数でデータを分割する事が可能ですよ。 Ubound()関数で配列の要素数を取得する事が出来ます。 Split関数で文字列を区切る http://officetanaka.net/excel/vba/tips/tips62.htm
補足
すみません。上手く説明が出来ていませんでした。 mydata(1)="あ,い,う,え,お" mydata(2) ="か,き,く,け,こ" ・ ・ と言う風に、mydata()の中にstringデーターが格納されている とします。 Option Base 1 Dim OutPutData As Variant Private Sub データー再格納() Dim myAry As Variant Dim a As Integer, b As Integer ReDim OutPutData(uboun(mydata), 5)<<<<(*) For a = LBound(mydata) To UBound(mydata) myAry = Split(mydata(a), ",") ReDim Preserve myAry(UBound(myAry) + 1) For b =LBound(myAry) to UBound(myAry) OutPutData(a,b) = myAry(b) Next b Next a End Sub (*)のところの「5」と言う数字をmydata(1)の文字列から取得する関数 と言うものが存在するのでしょうか? カンマの数が数えられれば、その数プラス1で取得できればと考えた のですが。 InStr関数をループで用いれば、取得できそうなのですが、特定の 文字をカウントする関数などあればと思い、ご質問させていただきました。
お礼
お返事ありがとうございます。 このような形でテストサンプルコードまで ご用意頂き誠にありがとうございます。 VBAを勉強させていただくに当たり、このような サンプルコード等を頂け誠にありがとうございます。 こういった形でコード読んでいきますと、自分の 理解できていなかった事や、コードの記述テクニック等 色々な面で勉強させていただけるので、とても 助かります。おかげさまでVBAを勉強始めてから 仕事の能率がかなりはかどっているしだいです。 誠にありがとうございます。 今後ともご質問させていただく機会はあると思いますが 宜しくお願いいたします。