教えてください。
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): 高さ が格納される ④配列0~2の値を列V~Tに出力する ⇒Cells(ループ行, "V") = 配列(0) Cells(ループ行, "U") = 配列(1) Cells(ループ行, "T") = 配列(2) (行ループここまで) ⑤対象範囲の最終行までループ処理
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/01/16 07:34

回答6件
0
ベストアンサー
もうほぼ自力で答えを出されていらっしゃると思いますが、やりたいことのもう一歩のところで手が止まってしまうってありますよね。
次のような形でいけると思います。
VBScript
1Sub 並び替え() 2Dim myRng As Range ' F列のデータ範囲 3Dim r As Range ' ループ作業用 4Dim v As Variant 5Dim i As Long 6 ' データ範囲をセット 7 Set myRng = Range(Cells(5, "F"), Cells(Rows.Count, "F").End(xlUp)) 8 9 'T列(高さ)、U列(横)、V列(縦)としたい 10 ' ループ処理 11 i = 5 12 For Each r In myRng 13 v = Split(r, "x") 14 If UBound(v) < 2 Then 15 Cells(i, "V") = v(LBound(v)) 16 Cells(i, "U") = v(LBound(v) + 1) 17 Else 18 Cells(i, "V") = v(LBound(v)) 19 Cells(i, "U") = v(LBound(v) + 1) 20 Cells(i, "T") = v(LBound(v) + 2) 21 End If 22 i = i + 1 23 Next 24 25End Sub
配列が0,1
の時と0,1,2
の時とがあることが分かっていますので、配列の上限を返すUBound
を使うことで判断できます。
LBound
は下限を返す関数です。
Bound
は境界。
LBound
のL
はたぶんLowerで下を示すのでLower Boundで下限(下界?)。
UBound
のU
はたぶんUpperで上を示すのでUpper Boundで上限(上界?)。
という意味合いになるかと思います。
#追記:ついでなので、こんな書き方もありますという例です。
まず、Excelのシートは次のようにしています。
コードは次の通りです。
VBScript
1Sub Hoge() 2On Error GoTo Err 3Dim targetCells As Range 4Dim readCell As Range 5Dim writeCell As Range 6Dim readArray As Variant 7Dim writeArray As Variant 8Dim i As Long, j As Long 9 10 Set targetCells = Range("F2", "F" & ActiveSheet.UsedRange.Rows(ActiveSheet.UsedRange.Rows.Count).Row) 11 Set writeCell = Range("T2") 12 13 Application.ScreenUpdating = False 14 For Each readCell In targetCells 15 ReDim writeArray(2) 16 readArray = Split(readCell, "x") 17 j = 2 18 For i = 0 To UBound(readArray) 19 writeArray(j) = readArray(i) 20 j = j - 1 21 Next 22 Range(writeCell, writeCell.Offset(, 2)) = writeArray 23 Set writeCell = writeCell.Offset(1) 24 Next 25Err: 26 Application.ScreenUpdating = True 27End Sub
逆にわかりづらくて混乱させるかもしれませんが、いくつか知って欲しいポイントがありますが、そんな方法もあるんだ程度に思ってください。
まず、セルの範囲を知る方法は色々とありますが、UsedRange
があります。
この例では、UsedRange
から、使われている最後の行の行番号を取得しています。
ただし、この方法はF
列以外の列でF
列以上のデータがあると正しい範囲を得られませんので、元々の方法である、.End(xlUp)
で最後に入力のあるセルを得る方がよいかもしれません。
ScreenUpdating
は、VBAを使い出した際に、大量データで処理が遅い時にかならずといっていいほど使う手段です。
ScreenUpdating
がFalse
だと画面の描画を一切更新しなくなります。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 00:24
編集2017/01/17 00:55総合スコア146
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
関数を自作してはどうでしょうか。
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 05:16
総合スコア1894
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/01/16 05:27
2017/01/16 05:44

0
マクロで作るなら
マクロで処理するならSplit関数で配列に格納し、任意の列に出力すれば目的の結果が得られると思います。
※今回はご自身で作成されたコードの提示がないため、具体的なサンプルコードの公開は控えさせていただきますm(__)m
処理手順としては
①2行目から対象範囲の最終行までループ処理 (行ループここから) ②ループ処理行のF列から値を取得 ③取得した値を"x"で分割(Split関数を利用) ⇒配列(0):縦 配列(1):横 配列(2):高さ が格納される ④配列0~2の値を列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 05:54
編集2017/01/17 00:20総合スコア3020
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
関数でも可能ですが、関数以外をご希望とのことで、サンプルをご紹介します。
※コメントを受けて、一部修正しました。
修正点1.xの大文字小文字不問(混在も可)
修正点2.パターンにマッチしない場合、配列に空欄をセット
※他の方が回答されているように、Split関数で分割する方法のほうが、わかりやすいかもしれません。
※高さが無い場合について、このマクロは本質的に対応できていません。従って実務においては、他の方が
提示されたSplit関数を使用されるほうがよいとおもいます。ただし正規表現も、覚えておけば絶対に
損はしないと思いますので、この機会に是非挑戦してみてください。
VBA
1Sub Sample() 2 3 Dim myRng As Range ' F列のデータ範囲 4 Dim r As Range ' ループ作業用 5 Dim myReg As Object ' 正規表現 6 Dim mc As Object ' Match Case 7 Dim buf As Variant ' データ格納用配列 8 Dim i As Long ' ループカウント用 9 Dim j As Integer ' ループカウント用 10 11' 正規表現使用準備 12 13 Set myReg = CreateObject("VBScript.RegExp") 14 15' データ範囲をセット 16 17 Set myRng = Range(Cells(2, "F"), Cells(Rows.Count, "F").End(xlUp)) 18 19' データ範囲から、配列を再定義 20 21 ReDim buf(1 To myRng.Count, 1 To 3) 22 23' パターン定義 24' ※1文字以上連続する数字の三つの塊が、「x」で繋がっているもの。 25' ※「\d」は、数字を表しています。「+」は、直前の文字が1回以上連続していることを意味しています。 26' ※従って、\d+は、1回以上連続する数字をあらわすことになります。 27' ※これを()で括ることによって、のちほど取り出すことができるようになります。 28 29 myReg.Pattern = "(\d+)x(\d+)x(\d+)" 30 31' ループ処理 32 33 i = 1 34 35 For Each r In myRng 36 37 ' Executeメソッドを用いて、対象となる文字列がパターンに一致した場合、それを 38 ' Matchコレクションに格納します。要は、後で使えるようにしています。 39 ' 半角数字も存在するとのことで、StrConv(r, vbLowerCase + vbNarrow)としました。 40 ' mc(0)となっているのは、パターンに合うものが各文字列に一つしかないためです。 41 ' 一つの文字列に、パターンに合うものが複数ある場合は、mc(1),mc(2)と続きます。 42 ' パターンにマッチした場合、一つ目の()がSubmatches(0)となります。後は同じ要領です。 43 44 Set mc = myReg.Execute(StrConv(r, vbLowerCase + vbNarrow)) 45 If myReg.test(StrConv(r, vbLowerCase + vbNarrow)) Then 46 buf(i, 1) = mc(0).submatches(2) 47 buf(i, 2) = mc(0).submatches(1) 48 buf(i, 3) = mc(0).submatches(0) 49 Else 50 For j = 1 To 3 51 buf(i, j) = "" 52 Next j 53 End If 54 i = i + 1 55 56 Next 57 58' データ貼り付け 59 60 Cells(2, "T").Resize(i - 1, 3) = buf 61 62 Set myRng = Nothing 63 Set myReg = Nothing 64 Set mc = Nothing 65 66End Sub
参考になれば、幸いです。
投稿2017/01/16 05:20
編集2017/01/16 23:27総合スコア38
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
marutokiさん、はじめまして。
もっとも簡単な方法は単純に、作業用に別のセルにその分割した値を貼り付けて、それを参照する形だと思います。
次の例は、X
Y
Z
のセルに「データ」⇒「区切り位置」で分割 した結果。
それをT
列はZ
列を、U
列はY
列を、V
列はX
列を参照することで、逆ならびにしています。
これではあまり望みの方法ではないでしょうか?
分割結果をX
Y
Z
でなくとも、もっと離れたセルにしても良いですし、隠しても良いですし、別シートにしてもよいです。
Excelでは、ワークシート関数などをいっぺんに呼ばなくても、途中途中の結果を作業用のセルに出力して、段階的に利用する手は最もよく使われている手法だと思います。
ただ、マクロを使ってみようという気持ちがありましたら、色々と便利になりますので、別途回答したいと思います。
投稿2017/01/16 05:18
総合スコア146
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

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 08:30
編集2017/01/16 08:35総合スコア146
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。