[[20160206133332]] 『『以下の場合、どのようなVBAコードになるでしょax(CBR1000RR) ページの最後に飛ぶ

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

 

『『以下の場合、どのようなVBAコードになるでしょうか?』(CBR1000RR) その2』(CBR1000RR)

『以下の場合、どのようなVBAコードになるでしょうか?』(CBR1000RR)

以下のような実行結果が出力されるマクロコードを教えて頂きたく。

元ファイル

  |C |G|M |Q
3 |P01|1|○|SD2,5-FAEFA-34P-DS
4 |P01|2|○|D-SW2,5-WWEFD
5 |P01|1|○|SD2,5-FAEFA-23P-DS
6 |P01|2|  |D-SW2,5-WWEFD
7 |P01|1|○|SD2,5-FAEFA-100P-DS
8 |P01|2|○|D-SW2,5-WWEFD
9 |P01|1|  |SD2,5-FAEFA-98P-DS
10|P01|2|  |D-SW2,5-WWEFD
11|P01|1|○|SD2,5-FAEFA-3P-DS
12|P01|2|○|D-SW2,5-WWEFD
13|P01|1|○|SD2,5-FAEFA-32P-DS
14|P01|1|  |SD2,5-34P-AS
15|P01|2|○|D-SW2,5
16|P01|1|○|SD2,5-100P-AS
17|P01|2|○|D-SW2,5
18|P01|1|○|SD2,5-36P-AS
19|P01|2|○|D-SW2,5
20|   | |  |
21|   | |  |
23|   | |  |
24|   | |  |
25|   | |  |
26|   | |  |
27|   | |  |
28|P20|1|○|SD2,5-FAEFA-34P-DS
29|P20|2|○|D-SW2,5-WWEFD
30|P20|1|○|SD2,5-FAEFA-64P-DS
31|P20|2|○|D-SW2,5-WWEFD

実行結果

 |C  |G|M |Q
3|P01|1|○|SD2,5-FAEFA-192P-DS
4|P01|6|○|D-SW2,5-WWEFD
5|P01|1|○|SD2,5-136P-AS
6|P01|6|○|D-SW2,5
7|P20|1|○|SD2,5-FAEFA-98P-DS
8|P20|4|○|D-SW2,5-WWEFD

の続きトピになります。

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


 要件が、任意の文字列パターン(でも、任意の特定文字列と数字と別の任意の特定文字列 という並び)を任意の数だけ与えたいということなら
 以下のタイプAでお試しください。
 そうではなく、前半の特定文字列が複数あり、そのあと数字、続いて 後半の特定文字列が複数。 
 で、前半の特定文字列と後半の特定文字列の組み合わせは任意ということなら以下のタイプBで試してください。

 (そちらがアップされたパターン例は、そのいずれとでも受け取れる内容でしたので)

 ところで、SD2,5-FAEFA- や P-DS 等、特定文字列を指定するうえで、もし、その文字列中に

 ^  $  ?  *  +  .  |  {  }  \  [  ]  (  )

 こんな文字が含まれている場合、それは正規表現処理にとって、特殊な制御文字(メタ文字)とみなされますので、
 \ をつけて(たとえば \+ や \( といったように)記述してくださいね。

 ●タイプA SubProc 入れ替え

 Sub subProc(ws As Worksheet, dic As Object, dicG As Object, dicAC As Object, reg As Object)
    Dim c As Range
    Dim key As Variant
    Dim n As Long
    Dim w As Variant
    Dim x As Long
    Dim mt As Object
    Dim rep As String
    Dim hit As Boolean
    Dim patQ As String
    Dim patD As String
    Dim nD As Variant
    Dim cols As Long
    Dim d As Variant
    Dim y As Long

    dic.RemoveAll
    dicG.RemoveAll
    dicAC.RemoveAll

    patQ = "(SD2,5-FAEFA-)(\d+)(P-DS)|(SD2,5-)(\d+)(P-AS)|(SD2,5-FAEFA-)(\d+)(P-AS)|(SD2,5-)(\d+)(P-DS)"
    patD = "^\d+"   '先頭の数字

    '各行の C,D(先頭の数字),Q(特定文字列は数値を除外したもの),R をキーとして集約

    With ws

        If .Range("AC2").Value = "" Then
            .Range("AC2").Value = "NUMBER"
        End If
        If .Range("AD2").Value = "" Then
            .Range("AD2").Value = "PLAE"
        End If

        cols = .Range("A1", .UsedRange).Columns.Count

        reg.Pattern = patD
        nD = Empty
        If reg.test(.Range("D3").Value) Then nD = reg.Execute(.Range("D3").Value)(0)

        'M列空白セルの行削除
        On Error Resume Next
        .Range("A1", .UsedRange).Offset(2).Columns("M").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
        On Error GoTo 0

        For Each c In .Range("C3", .Range("C" & Rows.Count).End(xlUp))

            reg.Pattern = patQ

            With c.EntireRow
                key = .Range("Q1").Value
                n = 0
                hit = False
                Set mt = reg.Execute(key)
                If mt.Count > 0 Then
                    hit = True
                    For y = 0 To mt(0).submatches.Count - 1 Step 3
                        If Not IsEmpty(mt(0).submatches(y)) Then
                            n = mt(0).submatches(y + 1)
                            key = reg.Replace(key, "$" & y + 1 & vbTab & "$" & y + 3)
                            Exit For
                        End If
                    Next

                    .Range("Q1").Value = key

                End If

                key = .Range("C1").Value & vbLf & nD & vbTab & key & vbTab & .Range("R1").Value

                If Not dic.exists(key) Then
                    dicAC(c.Value) = dicAC(c.Value) + 1
                    .Range("AC1").Value = nD & "-" & c.Value & "-" & dicAC(c.Value)

                    If c.Value = "S01" Then
                        .Range("AD1").Value = "M_MERKER"
                    Else
                        .Range("AD1").Value = "B_MERKER"
                    End If

                    dic(key) = c.EntireRow.Resize(, cols).Value

                End If

                If dicG.exists(key) Then
                    w = dicG(key)
                Else
                    w = Array(0, 0)
                End If

                w(0) = hit

                If hit Then
                    w(1) = w(1) + n
                Else
                    w(1) = w(1) + .Range("G1").Value
                End If

                dicG(key) = w

            End With
        Next

        'シート再作成

        For Each key In dic
            d = dic(key)
            w = dicG(key)
            If w(0) Then        'Q列特定文字列
                d(1, Columns("G").Column) = 1       '常に 1
                '特定文字列内の数値を合計値で置換
                If d(1, Columns("Q").Column) Like "*" & vbTab & "*" Then d(1, Columns("Q").Column) = Replace(d(1, Columns("Q").Column), vbTab, w(1))
            Else
                d(1, Columns("G").Column) = w(1)    'G列合計
            End If

            dic(key) = d
        Next

        .Range("A1", .UsedRange).Offset(2).ClearContents            'シートの3行目以降をクリア
        'dic に生成した変換シートイメージを一括転記
        .Range("A3").Resize(dic.Count, cols).Value = WorksheetFunction.Transpose(WorksheetFunction.Transpose(dic.items))

        'C列で並び替え
        .Range("C3", .Range("C" & Rows.Count).End(xlUp)).Offset(, -2).Resize(, cols).Sort Key1:=.Range("C3"), Order1:=xlAscending, Header:=xlNo

    End With

 End Sub

 ●タイプB SubProc 入れ替え

 Sub subProc(ws As Worksheet, dic As Object, dicG As Object, dicAC As Object, reg As Object)
    Dim c As Range
    Dim key As Variant
    Dim n As Long
    Dim w As Variant
    Dim x As Long
    Dim mt As Object
    Dim rep As String
    Dim hit As Boolean
    Dim patQ As String
    Dim patD As String
    Dim nD As Variant
    Dim cols As Long
    Dim d As Variant

    dic.RemoveAll
    dicG.RemoveAll
    dicAC.RemoveAll

    patQ = "(SD2,5-FAEFA-|SD2,5-)(\d+)(P-DS|P-AS)"     '
    patD = "^\d+"   '先頭の数字

    '各行の C,D(先頭の数字),Q(特定文字列は数値を除外したもの),R をキーとして集約

    With ws

        If .Range("AC2").Value = "" Then
            .Range("AC2").Value = "NUMBER"
        End If
        If .Range("AD2").Value = "" Then
            .Range("AD2").Value = "PLAE"
        End If

        cols = .Range("A1", .UsedRange).Columns.Count

        reg.Pattern = patD
        nD = Empty
        If reg.test(.Range("D3").Value) Then nD = reg.Execute(.Range("D3").Value)(0)

        'M列空白セルの行削除
        On Error Resume Next
        .Range("A1", .UsedRange).Offset(2).Columns("M").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
        On Error GoTo 0

        For Each c In .Range("C3", .Range("C" & Rows.Count).End(xlUp))

            reg.Pattern = patQ

            With c.EntireRow
                key = .Range("Q1").Value
                n = 0
                hit = False
                Set mt = reg.Execute(key)
                If mt.Count > 0 Then
                    hit = True
                    key = reg.Replace(key, "$1" & vbTab & "$3")
                    n = mt(0).submatches(1)
                    .Range("Q1").Value = key
                End If

                key = .Range("C1").Value & vbLf & nD & vbTab & key & vbTab & .Range("R1").Value

                If Not dic.exists(key) Then
                    dicAC(c.Value) = dicAC(c.Value) + 1
                    .Range("AC1").Value = nD & "-" & c.Value & "-" & dicAC(c.Value)

                    If c.Value = "S01" Then
                        .Range("AD1").Value = "M_MERKER"
                    Else
                        .Range("AD1").Value = "B_MERKER"
                    End If

                    dic(key) = c.EntireRow.Resize(, cols).Value

                End If

                If dicG.exists(key) Then
                    w = dicG(key)
                Else
                    w = Array(0, 0)
                End If

                w(0) = hit

                If hit Then
                    w(1) = w(1) + n
                Else
                    w(1) = w(1) + .Range("G1").Value
                End If

                dicG(key) = w

            End With
        Next

        'シート再作成

        For Each key In dic
            d = dic(key)
            w = dicG(key)
            If w(0) Then        'Q列特定文字列
                d(1, Columns("G").Column) = 1       '常に 1
                '特定文字列内の数値を合計値で置換
                If d(1, Columns("Q").Column) Like "*" & vbTab & "*" Then d(1, Columns("Q").Column) = Replace(d(1, Columns("Q").Column), vbTab, w(1))
            Else
                d(1, Columns("G").Column) = w(1)    'G列合計
            End If

            dic(key) = d
        Next

        .Range("A1", .UsedRange).Offset(2).ClearContents            'シートの3行目以降をクリア
        'dic に生成した変換シートイメージを一括転記
        .Range("A3").Resize(dic.Count, cols).Value = WorksheetFunction.Transpose(WorksheetFunction.Transpose(dic.items))

        'C列で並び替え
        .Range("C3", .Range("C" & Rows.Count).End(xlUp)).Offset(, -2).Resize(, cols).Sort Key1:=.Range("C3"), Order1:=xlAscending, Header:=xlNo

    End With

 End Sub

(β) 2016/02/07(日) 18:21


 元スレにも投稿済みですが、例題のデータから期待値への変換は下記コードでできています。

 他に条件変更等あれば、対応はしやすいと思いますよ?

  Sub test()
    Dim a, i As Long, ii As Long, x, temp As String, dic As Object, myNum As Long
    Set dic = CreateObject("Scripting.Dictionary")
    Wit [a3].CurrentRegion.Resize(, 17)
        x = Filter(Evaluate("transpose(if(" & .Columns(13).Address & _
        "=""○"",row(1:" & .Rows.Count & "),char(2)))"), Chr(2), 0)
        a = Application.Index(.Value, Application.Transpose(x), [{3,7,13,17}])
    End With
    With CreateObject("VBScript.RegExp")
        .Pattern = "(SD2,5(-FAEFA)?-)(\d+)(P-[AD]S)$"
        For i = 1 To UBound(a, 1)
            If .test(a(i, 4)) Then
                temp = Join(Array(.Replace(a(i, 4), "$1$4"), a(i, 1)), Chr(2))
                If Not dic.exists(temp) Then
                    dic(temp) = dic.Count + 1
                    SwapArray a, dic.Count, i
                Else
                    myNum = Val(.Replace(a(i, 4), "$3")) + Val(.Replace(a(dic(temp), 4), "$3"))
                    a(dic(temp), 4) = .Replace(a(dic(temp), 4), "$1" & myNum & "$4")
                End If
            Else
                temp = Join(Array(a(i, 4), a(i, 1)), Chr(2))
                If Not dic.exists(temp) Then
                    dic(temp) = dic.Count + 1
                    SwapArray a, dic.Count, i
                Else
                    a(dic(temp), 2) = a(dic(temp), 2) + a(i, 2)
                End If
            End If
        Next
    End With
    Sheets.Add.Cells(1).Resize(dic.Count, 4).Value = a
End Sub

 Private Sub SwapArray(a, ref As Long, i As Long)
    Dim ii As Long
    For ii = 1 To UBound(a, 2)
        a(ref, ii) = a(i, ii)
    Next
End Sub

 FileをUL
http://firestorage.jp/download/b132c2f9d1e4cb5829af169a9ac654a93564fb8d 
 ダウンロードパスワード yedvxw7e
(seiya) 2016/02/07(日) 20:53

 失礼します。

 seiyaさんのパターン、いつもながら感服なんですが、質問者さんのアップされたケースが、もしかしたら【たまたま】のケースかなと。
 なので、私がアップしたコードも、2つの解釈をしていまして、どちらが、本当なのか、あるいは、どちらも勘違いなのか。
 もしかしたら、seiyaさんの解釈、つまり

 最初の文字列は SD2,5- もしくは SD2,5-FAEFA- いずれか。(FAEFA- があるケースとないケースだけ)
 後ろの文字列は P-DS か P-AS いずれか。違いは D か A か というところだけ。

 このように限定されているというのが、正しい解釈なのかもしれませんね。

 ちなみに、私は

 AAA 数字 XXX
 BBB 数字 YYY
 CCC 数字 ZZZ

 といったように任意の文字列を複数与えたいのかな?(これが私がアップした タイプAです)

 ないしは

 最初の文字列は AAA または BBB または CCC。 後ろの文字列は XXX または YYY。
 最初の文字列と後ろの文字列の組み合わせは任意。 AAA 数字 YYY もマッチ、CCC 数字 XXX もマッチ。

 というようなことなのかな?と。(これが私がアップした タイプBです)

 このあたりは、質問者さんから明確な要件の定義を聞かせていただきたいところです。

 (もちろん、質問者さんが、正規表現のパターンの与え方については熟知していて、実際に抽出したい文字列要件に従って
  適切なパターンを随時組み立てられるなら、どんな解釈云々という話ではないのですけど)

(β) 2016/02/07(日) 21:46


 元スレに
 >⇒特定の文字列はSD2,5-FAEFA-(数値)P-DSとSD2,5-(数値)P-ASの二つのみです。
    この二つ以外は存在しないと考えて下さい。
 との明確な記述があったので、それに基づいて書いたコードです。
(seiya) 2016/02/07(日) 21:59

βさん

返答遅くなってしまい、すみません。
タイプAで問題なく動作しました。
タイプBも必要な場面は十分にありそうですので、その際は利用させてもらいます。

非常に長く、お付き合い頂き、有難う御座います。
本当に助かりました!!

(CBR1000RR) 2016/02/08(月) 10:39


seiyaさん

返答遅くなってしまい、すみません。
こちらのコードも非常に助かりました。
御助力頂き、有難う御座います。
(CBR1000RR) 2016/02/08(月) 10:41


 >御助力頂き、有難う御座います。

 この質問にもっと早く気が付いていれば...
 私のコードは簡単・簡潔に書いてあるのでStep Debug すれば理解できると思いますよ?
(seiya) 2016/02/08(月) 10:54

seiyaさん

いえいえ、回答頂けただけでも助かります。
上記デバックにて確認してみます。

ありがとうございます。
(CBR1000RR) 2016/02/08(月) 13:08


コメント返信:

[ 一覧(最新更新順) ]


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