質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.33%

  • VBA

    1906questions

    VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

  • Excel

    1643questions

    Excelは、マイクロソフト社が開発しているデータ集計や分析を行う表計算ソフトの一つです。文書作成や表計算、資料作成などの多彩な機能を備えており、統合パッケージであるMicrosoft Officeに含まれています。

エクセル VBA 1つのセルの値を分けて、逆並びで列に配置

解決済

回答 6

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,499

marutoki

score 10

教えてください。

F列2行目から例えば、
43x43x5(×は大文字のx(エックス)で代用してます。)
というサイズ「縦x横x高さ」が入力されています。
これを数値ごとに分割して、
T列(高さ)、U列(横)、V列(縦)としたいです。

エクセルの基本設定で「データ」⇒「区切り位置」で分割はできるのですが、
これを逆向きに配置するというのはやはりマクロでないと不可能でしょうか?

出来れば数値はコピー貼り付けしたいので、関数ではなく
エクセルの書式設定や基本設定、もしくはマクロで良い方法がないでしょうか?

【追記】
rrryutaro様の教えによりなんとか下記コードで動作しました。
ただ、あくまで「縦x横x高さ」すべてそろっている場合で、
高さのないもの(「縦x横」)があると、当然ですが、
「インデックスが有効範囲にありません。」
となります。
Splitで抽出したvの値は0,1,2ですよね?
これを0,1の時、0,1,2の時で処理を分ける必要がある。
例えば v = Split(r, "x")の後に
IF文を入れて、
V=0,1のみ then
Cells(i, "V") = v(LBound(v))
Cells(i, "U") = v(LBound(v) + 1)
else
Cells(i, "V") = v(LBound(v))
Cells(i, "U") = v(LBound(v) + 1)
Cells(i, "T") = v(LBound(v) + 2)

う~ん、
このあたりの書き方がなんとも分かりません・・・。

Sub 並び替え()

    Dim myRng   As Range    ' F列のデータ範囲
    Dim r       As Range    ' ループ作業用
    Dim v As Variant
    Dim i As Long

' データ範囲をセット
    Set myRng = Range(Cells(5, "F"), Cells(Rows.Count, "F").End(xlUp))

    'T列(高さ)、U列(横)、V列(縦)としたい
    ' ループ処理
    i = 5
    For Each r In myRng
    v = Split(r, "x")
        Cells(i, "V") = v(LBound(v))
        Cells(i, "U") = v(LBound(v) + 1)
        Cells(i, "T") = v(LBound(v) + 2)
        i = i + 1
    Next

End Sub

①2行目から対象範囲の最終行までループ処理
(行ループここから)
 ②ループ処理行のF列から値を取得
 ③取得した値を"x"で分割(Split関数を利用)
  ⇒配列 (0): 縦
   配列 (1): 横
   配列 (2): 高さ が格納される
 ④配列02の値を列V~Tに出力する
  ⇒Cells(ループ行, "V") = 配列(0)
   Cells(ループ行, "U") = 配列(1)
   Cells(ループ行, "T") = 配列(2)
(行ループここまで)
⑤対象範囲の最終行までループ処理
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • rrryutaro

    2017/01/16 15:03 編集

    「関数ではなく」の一言が皆さん結構引っかかって、回答を悩んでいる部分があるかと思います。これが具体的に何を指しているのかが一言あると回答の助けになります。
    例えば、Excelでの分割した結果にワークシート関数を使用した場合、それをコピーして、それをまたExcelに貼り付けた場合、ワークシート関数をコピーしてしまうことの懸念でしたら、jawaさんの提示する別案①の方法で解決できます。

    キャンセル

  • marutoki

    2017/01/16 16:25

    ありがとうございます。「関数ではなく」の部分は数値としてコピーしたい、しかも条件付き貼り付けをせずに、という思いからです。jawaさんの別案①については、 一番確実かつ簡単ですが、コピーするのが第三者(もっと初心者)であるため注釈などが必要となりシステムとして使いづらいものになってしまいます。

    キャンセル

  • rrryutaro

    2017/01/16 16:34

    はい。状況がよくわかりました。回答ありがとうございます。

    キャンセル

回答 6

checkベストアンサー

+5

もうほぼ自力で答えを出されていらっしゃると思いますが、やりたいことのもう一歩のところで手が止まってしまうってありますよね。
次のような形でいけると思います。

Sub 並び替え()
Dim myRng   As Range    ' F列のデータ範囲
Dim r       As Range    ' ループ作業用
Dim v As Variant
Dim i As Long
    ' データ範囲をセット
    Set myRng = Range(Cells(5, "F"), Cells(Rows.Count, "F").End(xlUp))

    'T列(高さ)、U列(横)、V列(縦)としたい
    ' ループ処理
    i = 5
    For Each r In myRng
        v = Split(r, "x")
        If UBound(v) < 2 Then
            Cells(i, "V") = v(LBound(v))
            Cells(i, "U") = v(LBound(v) + 1)
        Else
            Cells(i, "V") = v(LBound(v))
            Cells(i, "U") = v(LBound(v) + 1)
            Cells(i, "T") = v(LBound(v) + 2)
        End If
        i = i + 1
    Next

End Sub

配列が0,1の時と0,1,2の時とがあることが分かっていますので、配列の上限を返すUBoundを使うことで判断できます。
LBoundは下限を返す関数です。
Boundは境界。
LBoundLはたぶんLowerで下を示すのでLower Boundで下限(下界?)。
UBoundUはたぶんUpperで上を示すのでUpper Boundで上限(上界?)。
という意味合いになるかと思います。

追記:ついでなので、こんな書き方もありますという例です。

まず、Excelのシートは次のようにしています。
イメージ説明

コードは次の通りです。

Sub Hoge()
On Error GoTo Err
Dim targetCells As Range
Dim readCell As Range
Dim writeCell As Range
Dim readArray As Variant
Dim writeArray As Variant
Dim i As Long, j As Long

    Set targetCells = Range("F2", "F" & ActiveSheet.UsedRange.Rows(ActiveSheet.UsedRange.Rows.Count).Row)
    Set writeCell = Range("T2")

    Application.ScreenUpdating = False
    For Each readCell In targetCells
        ReDim writeArray(2)
        readArray = Split(readCell, "x")
        j = 2
        For i = 0 To UBound(readArray)
            writeArray(j) = readArray(i)
            j = j - 1
        Next
        Range(writeCell, writeCell.Offset(, 2)) = writeArray
        Set writeCell = writeCell.Offset(1)
    Next
Err:
    Application.ScreenUpdating = True
End Sub


実行結果は次のようになります。
イメージ説明

逆にわかりづらくて混乱させるかもしれませんが、いくつか知って欲しいポイントがありますが、そんな方法もあるんだ程度に思ってください。

まず、セルの範囲を知る方法は色々とありますが、UsedRangeがあります。
この例では、UsedRangeから、使われている最後の行の行番号を取得しています。
ただし、この方法はF列以外の列でF列以上のデータがあると正しい範囲を得られませんので、元々の方法である、.End(xlUp)で最後に入力のあるセルを得る方がよいかもしれません。

ScreenUpdatingは、VBAを使い出した際に、大量データで処理が遅い時にかならずといっていいほど使う手段です。
ScreenUpdatingFalseだと画面の描画を一切更新しなくなります。Trueにすることで、通常通り更新されるようになります。つまり、セルへの書き込みなどを描画しないので速くなりますが、Trueにし忘れると、何も反応が無くなったようになり、戻し方が分からなければExcelを終了せざる終えなくなりますので、注意が必要です。

このため、On Error Goto Errとして、エラーが発生した場合、Err:ラベルへジャンプするようにして、必ずScreenUpdatingをTrueにするようにしています。

後は配列は0 to 2固定と考えて、書き込み用の配列を作成し、後ろから値を入れて、セル範囲に配列で書き込んでいます。

セルの操作は相対参照するようにしています。まず最初にSet writeCell = Range("T2")として書き込みするセルの開始点を設定します。

値を貼り付ける時は、T~Vとなるように、.Offset(, 2)として、自身から2列離れたセルを参照させています。
最後に、.Offset(1)としてひとつしたのセルへと設定しています。

この辺のセル操作はそれぞれに好みのやり方もあるかと思いますが、Excel VBAでもっとも重要といってもよいくらいRangeオブジェクトは重要だと自分は考えています。

以上

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/17 10:59

    質問に対する解答だけでなく、コードの意味や考え方まで丁寧に教えていただいて感謝感激です!
    サンプルコードも非常に勉強になります。
    よく見ると、「40R」とかもあり、私のマクロでは動きませんでした(-_-;)
    また、IFで増やせばよいのですが・・・
    しかし、サンプルコードなら.splitで取得した値が0~2まで対応できますね。
    .rangeも大切ですが、For~Next中の.offset(1)で行数を増やしていくという仕組みがようやく分かりました。
    入れ子やReDimとか、まだまだ自分では考え付きませんので経験を積んでいこうと思います。
    ありがとうございました。

    キャンセル

  • 2017/01/17 12:37

    自分もteratailをはじめたばかりということもあり、どこまで質問に答えられるかという練習をしているようなところもありますので、参考になれば何よりです。
    頑張ってください!

    キャンセル

+2

関数を自作してはどうでしょうか。

Function RevStr(orgStr As String)
    myAr = Split(orgStr, "x")

    RevStr = myAr(2) & "x" & myAr(1) & "x" & myAr(0)
End Function

ワークシート上で一般の関数と同様、セルに"=RevStr(A1)"という感じで使用します。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/16 14:25

    「関数ではなく」とあったのですね…
    お気に召さなければ無視していただいて結構ですが、関数でも「数値はコピー貼り付けしたい」要望はかなえられると思うのですがいかがでしょうか。

    キャンセル

  • 2017/01/16 14:27

    ynakanoさんの方法が、マクロを使った場合のシンプルな方法のひとつでいいですね。
    でも、折角ならば、引数を1つ増やして、配列の何番目を返すかのインデックスにしてしまえば、それぞれ、T列、U列、V列に直接結果を返せるのでより便利だと感じました。
    さらについでにデリミタも指定すればさらに汎用的になるかと思います。

    自分も関数を用意してみようかと思いましたが、ynakanoさんの方法でまずは十分なので、こちらにコメントさせていただきました。

    キャンセル

  • 2017/01/16 14:39

    正直、何に・どのように使われるのかが不明な(質問文以上の事が読み取れない)状況で必要以上に汎用性を追い求める事が良いこととは思わないです。
    利用するにあたり複雑性が増し、処理速度も(気にならないかもしれませんが)確実に遅くなるはずです。
    作る側としては汎用性の高いものをと思うのはよく分かるのですが、やりたい事とのバランスで最もシンプルな実装をする方がよいと考えています。

    キャンセル

  • 2017/01/16 14:44

    そのような方針だったのですね。おっしゃる意味よくわかります。
    特にこうした場では質問者に合わせることを考えると、余計な情報があることで理解を妨げてしまう可能性もありますので、まずはシンプルな回答を提示して、そこからリアクションをもらう方がよいですよね。

    キャンセル

  • 2017/01/16 15:39

    すみません、高尚なコメントをいただいて恐縮なのですが、
    初心者に毛が生えたようなレベルなので使い方をもう少し教えてください。
    あと回答0の方にも書いていますが、高さのない商品もあります・・・。
    たぶん使い方も違うでしょうが、
    T列に =RevStr(F1) といれるとそのままセルに「45x45x5」と入ります。

    ただ、今回作成する表は値をコピーして貼り付けるのが、さらに初心者の方で、条件付き貼り付けで値のみとか、難しいので数値として取り出せるマクロにしたかった次第です。

    余談ですが、質問する際、どこまで情報を提供するかは悩むところで、
    情報が多すぎると、本来質問したい部分が埋もれてなかなか思っていた回答が得られない場合が多いです。
    もちろん初心者としては汎用性があって、理解し易くて、応用がしやすい
    というのが一番なんですが。
    また、長々と手順やマクロを書いていただたあとで、いや~ちょっと違うんだよな~。
    となると、申し訳なくて申し訳なくて・・・

    なので、rrryutaroさんも回答されているように最初はシンプルな回答でいただけると助かります。こちらも核となる部分だけを質問し、芋づる式にすり合わせていきたいです。

    キャンセル

  • 2017/01/16 15:46

    使い方は合ってますよ。
    簡単にですが自分でも動作確認してます。元の文字列が全て表示されているのを見ると、区切り文字が一致しないのでしょうか…

    「高さがない」ケースについては、UBound関数を使ってmyAr配列の要素数を調べ、その数によって処理を分ければよいかと思います。
    縦横高さ全てあれば配列要素数は3でしょうし、縦横だけなら2になるはずですので。

    キャンセル

+1

marutokiさん、はじめまして。
もっとも簡単な方法は単純に、作業用に別のセルにその分割した値を貼り付けて、それを参照する形だと思います。

次の例は、X Y Zのセルに「データ」⇒「区切り位置」で分割 した結果。
それをT列はZ列を、U列はY列を、V列はX列を参照することで、逆ならびにしています。
イメージ説明

これではあまり望みの方法ではないでしょうか?

分割結果をX Y Zでなくとも、もっと離れたセルにしても良いですし、隠しても良いですし、別シートにしてもよいです。
Excelでは、ワークシート関数などをいっぺんに呼ばなくても、途中途中の結果を作業用のセルに出力して、段階的に利用する手は最もよく使われている手法だと思います。

ただ、マクロを使ってみようという気持ちがありましたら、色々と便利になりますので、別途回答したいと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/16 16:21

    ありがとうございます。
    一番身の丈に合った方法です。
    ただ、もっと初心者の第三者がコピペして使うものなのでT~V列は数値として転記したいです。
    また、他の方の回答にも書きましたが、高さのない商品もあります。

    キャンセル

  • 2017/01/16 16:33

    はい。他の回答者へのコメントで状況が理解できました。
    状況的には、ynakanoさんの反転した結果を分割してT~V列に転記すれば、第三者の方がコピペで困らないかと思います。

    あるいは、marutokiさん自身が提供する際に、形式を選択して貼り付けしなおす手もあるかもとは思いますが、手間がかかりますよね。

    一番いいのは、Subプロシージャを呼べば一発で、高さが無い場合も考慮してT~V列に反転した結果が貼りつくことだと思いますが、少しマクロが難しくなると思います。

    キャンセル

+1

関数でも可能ですが、関数以外をご希望とのことで、サンプルをご紹介します。

※コメントを受けて、一部修正しました。
修正点1.xの大文字小文字不問(混在も可)
修正点2.パターンにマッチしない場合、配列に空欄をセット

※他の方が回答されているように、Split関数で分割する方法のほうが、わかりやすいかもしれません。

※高さが無い場合について、このマクロは本質的に対応できていません。従って実務においては、他の方が
提示されたSplit関数を使用されるほうがよいとおもいます。ただし正規表現も、覚えておけば絶対に
損はしないと思いますので、この機会に是非挑戦してみてください。

Sub Sample()

    Dim myRng   As Range    ' F列のデータ範囲
    Dim r       As Range    ' ループ作業用
    Dim myReg   As Object   ' 正規表現
    Dim mc      As Object   ' Match Case
    Dim buf     As Variant  ' データ格納用配列
    Dim i       As Long     ' ループカウント用
    Dim j       As Integer  ' ループカウント用

' 正規表現使用準備

    Set myReg = CreateObject("VBScript.RegExp")

' データ範囲をセット

    Set myRng = Range(Cells(2, "F"), Cells(Rows.Count, "F").End(xlUp))

' データ範囲から、配列を再定義

    ReDim buf(1 To myRng.Count, 1 To 3)

' パターン定義
' ※1文字以上連続する数字の三つの塊が、「x」で繋がっているもの。
' ※「\d」は、数字を表しています。「+」は、直前の文字が1回以上連続していることを意味しています。
' ※従って、\d+は、1回以上連続する数字をあらわすことになります。
' ※これを()で括ることによって、のちほど取り出すことができるようになります。

    myReg.Pattern = "(\d+)x(\d+)x(\d+)"

' ループ処理

    i = 1

    For Each r In myRng

  ' Executeメソッドを用いて、対象となる文字列がパターンに一致した場合、それを
  ' Matchコレクションに格納します。要は、後で使えるようにしています。
  ' 半角数字も存在するとのことで、StrConv(r, vbLowerCase + vbNarrow)としました。
  ' mc(0)となっているのは、パターンに合うものが各文字列に一つしかないためです。
  ' 一つの文字列に、パターンに合うものが複数ある場合は、mc(1),mc(2)と続きます。
  ' パターンにマッチした場合、一つ目の()がSubmatches(0)となります。後は同じ要領です。

        Set mc = myReg.Execute(StrConv(r, vbLowerCase + vbNarrow))
        If myReg.test(StrConv(r, vbLowerCase + vbNarrow)) Then
            buf(i, 1) = mc(0).submatches(2)
            buf(i, 2) = mc(0).submatches(1)
            buf(i, 3) = mc(0).submatches(0)
        Else
            For j = 1 To 3
                buf(i, j) = ""
            Next j
        End If
        i = i + 1

    Next

' データ貼り付け

    Cells(2, "T").Resize(i - 1, 3) = buf

    Set myRng = Nothing
    Set myReg = Nothing
    Set mc = Nothing

End Sub

参考になれば、幸いです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/16 15:13

    超初心者ですので、理解がぎりぎりのマクロですが・・・
    すみません。
    大前提を崩してしまうのですが、高さがない商品もありまして・・・
    Cells(2, "T").Resize(i - 1, 3) = buf   でエラーになってしまいます。

    myReg.Pattern = "(\d+)X(\d+)X(\d+)"
    のXは様々な制約上x(全角小文字のエックス)に変えましたが問題ないでしょうか。

    キャンセル

  • 2017/01/16 16:21

    回答を一部修正しましたので、ご参考ください。

    キャンセル

  • 2017/01/17 00:40

    修正いただきありがとうございます。
    かなり上級なため、できましたとしか言えないのがつらいですが。
    また大前提の話ですが、無事動作完了するのですが、
    全角数字では反映されないのですねorz
    全角で質問して満足してましたがいろいろな制約で数値も全て全角になっています。
    全角数字を半角にするマクロを調べて勉強してから利用させていただきます。

    キャンセル

  • 2017/01/17 08:30

    「全角を半角に」ということで、マクロを修正しました。
    また、コメントも少し追記しました。

    私も専門は情報系ではなく、Net上で受けた数々のご指南に育てていただきました。
    従って、コメントやマクロの内容に誤りなどありましたら、ご容赦くださいm(_ _)m

    キャンセル

+1

マクロで作るなら

マクロで処理するならSplit関数で配列に格納し、任意の列に出力すれば目的の結果が得られると思います。
※今回はご自身で作成されたコードの提示がないため、具体的なサンプルコードの公開は控えさせていただきますm(__)m

処理手順としては

2行目から対象範囲の最終行までループ処理
(行ループここから)
 ②ループ処理行のF列から値を取得
 ③取得した値を"x"で分割(Split関数を利用)
  ⇒配列(0):縦
   配列(1):横
   配列(2):高さ  が格納される
 ④配列02の値を列V~Tに出力する
  ⇒Cells(ループ行,"V")=配列(0)
   Cells(ループ行,"U")=配列(1)
   Cells(ループ行,"T")=配列(2)
(行ループここまで)
⑤対象範囲の最終行までループ処理


のような流れになると思います。

別案①

ちなみに、コピーしたいからExcel関数は避けたい、というのはよくわかります。
関数で簡単に実現できるけど、値で作りたい。でもいちいちマクロを作るのは面倒だ…という場合、関数で目的の結果を作成した後に対象範囲全体を「コピー」⇒同じ範囲に「値の貼り付け」とすることで最終的に値で作成することもできます。

別案②

今回の場合、
>「データ」⇒「区切り位置」で分割はできる
とのことですので、これで作成したシートの列を並べ替えるマクロを作成する、という方法もあります。

別案③

自分ならどうするかを考えた時、Excelに持ってくる前に加工してしまう方法を取りそうな気がします。

正規表現置換を使えるテキストエディタで事前に加工しておくと、Excelでもできるけど多少面倒なことが意外と簡単にできてしまったりします。

今回の場合、
^(.+)x(.+)x(.+)$

\3\t\2\t\1
に置き換える正規表現置換を行うと、そのままエクセルに貼り付ける形が用意できます。

ExcelでもVBAでもないアドバイスになってしまいますが、今回のニーズにマッチしそうだったのでご紹介してみました。

参考になれば幸いです。

追記:サンプルコード
サンプル公開を控えたのは丸投げ対策でしたが、marutokiさんからは学習意欲がみられるのでサンプルコードを提供させていただきます。

Sub test()

    Dim sht As Worksheet    '対象シート
    Set sht = ActiveSheet   '今回はとりあえずアクティブシートを対象シートに設定

    Dim iRow As Integer     '行ループ
    Dim iIdx As Integer     '配列から値を取得する

    Dim strVal As String    'F列セル値
    Dim aryVal() As String  '分割結果

    '2行目からF列最終行までループ処理
    For iRow = 2 To sht.Cells(Rows.Count, "F").End(xlUp).Row
        'F列から値を取得
        strVal = sht.Cells(iRow, "F").Value

        '取得した値を"x"で分割
         aryVal = Split(strVal, "x")

        '縦・横・高さのループ処理(配列の個数だけループ処理)
        For iIdx = 0 To UBound(aryVal) - 1

            If iIdx > 2 Then Exit For '3回以上はループしない。(1x2x3x4でも3まで処理)

            '1回目:V列(22列)、2回目U列(21列)、3回目T列(20列)に値を出力
            sht.Cells(iRow, 22 - iIdx).Value = aryVal(iIdx)

        Next iIdx

    Next iRow

End Sub

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/16 16:16

    ありがとうございます。
    とりあえず、本案が稼働するよう勉強したいと思います。

    別案①については、
    一番確実かつ簡単ですが、コピーするのが第三者(もっと初心者)であるため注釈などが必要となりシステムとして使いづらいものになってしまいます。

    別案②については、
    これが一番私の身の丈に合っている方法だと思います。
    ただ無駄な列やシートを使わずやりたいという思いは理解いただけたらと思います。

    別案③については、
    勉強不足で初めて聞きました。
    正規表現置換ですか、勉強します。

    キャンセル

  • 2017/01/16 16:52

    第三者がコピー作業を行うのであれば、別案③も難しそうですね(^-^;

    サンプル公開を控えたのは丸投げ対策でしたが、marutokiさんからは理解しようという意欲がみられますのでサンプルコードを提供させていただきます。

    わかりにくいところなどあればご質問ください。

    キャンセル

  • 2017/01/16 18:00

    ありがとうございます。

    一応、本案でいただいたアドバイスを元にやってみましたが、なかなか・・・
    (質問に追記しています)

    もちろん、できました!あざ~す!で終わるつもりはありません。
    正直現場作業もあり、なかなかマクロに集中できる環境になく、学習速度はかなり遅いです(笑)
    ですが、マクロを知れば知るほど私のような小規模事業者にとって必須だなと実感しております。
    質問する以上、最低限の知識は身に付けたく、VBAエキスパート ベーシック合格に向け勉強中です。

    イメージは沸くのに形にできないもどかしい現状ですので今しばらくお力添えをいただければ幸いです。

    キャンセル

  • 2017/01/17 09:36

    追記拝見しました。
    Splitした時に要素が少ない場合のことを懸念されているようですね。

    私が紹介したサンプルではそこらへんも考慮されていますので、ちょっと解説しますね。

    ポイント①
    ---
    まずSplit関数ですが、
    「1x2x3」を"x"で分割すると3つの要素に分解され、
    「1x2」を分解すると2つの要素に分解されます。

    この要素の数を取得するのがUBoundという関数です。
    UBound関数を使うと、「1x2x3」を分解したときには3、「1x2」を分解したときには2という値を返してくれます。


    ポイント②
    ---
    私が紹介したサンプルコードでUBound関数で取得した要素数をどう使っているかというと
    ```
    For iIdx = 0 To UBound(aryVal) - 1
    ```
    という具合にループ処理のMax値として利用しています。
    配列の要素数応じてループ回数を増減させているということです。

    ここで配列の要素数-1としている理由は、インデックス値として利用するためです。
    「1x2x3」の要素数Uboound(aryVal)は3ですが、配列から値を取り出すときにはaryVal(0)~aryVal(2)で取り出しますので、0~2のループとなるように3-1としているわけです。

    ループ1周目は縦の要素の値を取得するので、V列(22列目)に出力します。
    ループ2周目は横の要素の値を取得するので、U列(21列目)に出力します。
    ループ3周目は高さの要素の値を取得するので、T列(20列目)に出力します。

    これを実現しているのが
    ```
    '1回目:V列(22列)、2回目U列(21列)、3回目T列(20列)に値を出力
    sht.Cells(iRow, 22 - iIdx).Value = aryVal(iIdx)
    ```
    の部分です。

    当然ですが要素数が2の場合はループが2周しか回りませんので、T列は出力されません。


    この仕組みが理解できればmarutokiさん作成のコードにも応用できると思います。
    頑張ってみてください。

    キャンセル

  • 2017/01/17 11:13

    ありがとうございます!すみません、先に読んでいたrrryutaro様をBAに選ばさせてもらいましたが、
    jawa様の回答も同等に非常に分かりやすく助かりました!
    なにせサイズは手入力ですから何が起こるか分かりません。
    .Splitで取得する数を
    If iIdx > 2 Then Exit For
    で制限するとエラーも出ず助かります。
    For~Nextの入れ子で対応はとても応用が利きますね。
    セルへの転記の仕方もいろいろあるのだと勉強になりました!
    また分からないことがあれば質問させてください。

    キャンセル

0

marutokiさん! splitの指定がmyRngになっていますよ!
rでなくてはなりません。
また結果の受け取りは別途Variant型の変数を用意してください。

念のため簡単に解説します。
例えば、F列が次のようになっていた場合

- F列
2 1x2x3
3 2x3
4 3x4x5


myRngは次のような配列になっています。
F2のセル, F3のセル, F4のセル
For Each r In myRngはmyRngの配列を1つずつ取り出して、rに格納します。

次のようにする必要があります。

Dim v As Variant
  :
v = Split(r, "x")

ちなみに、デバッグ機能は利用されていますでしょうか?
別件での回答になりますが、次の質問での回答でデバッグの使い方を少し説明してますので参考にしていただければと思います。
VBA - VBA 配列(62043)|teratail

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/16 23:49

    分かりやすい解説ありがとうございます。
    r In myRngとした時点でrに格納されている、言われれば確かにとは思うのですが・・・、デバック機能もF8で進めるとかなんとなくでしか理解できていません。これが先へ進めない原因でしょうね・・・。
    エラーがあるたびやろうとしていますが、すでにエラーの事で頭がいっぱいになるため、まずは正常動作品でどういう動きをしているかを確認するツールとして使ってみながらやった方が理解しやすいかもしれません。

    キャンセル

同じタグがついた質問を見る

  • VBA

    1906questions

    VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

  • Excel

    1643questions

    Excelは、マイクロソフト社が開発しているデータ集計や分析を行う表計算ソフトの一つです。文書作成や表計算、資料作成などの多彩な機能を備えており、統合パッケージであるMicrosoft Officeに含まれています。