ちょっと生きづらさを抱えた人へ、気持ちを楽にするためのお手紙です。

【VBA】枝番を振る

筆箱にカンニングペーパーを入れる係のみすくです。こんにちは。
VBA関連だけまとめたブログもあります。
筆箱VBA


階層がある項目に枝番をふります。
エラーチェックは入れていないので、
枝番をふられる対象の項目が、
ちゃんと書かれていることが前提。

枝番の階層を変更したいときは、
ワークシートの列を増減させて、
LEVEL_NUMに何階層まであるか、
eCOLに追加した列の分のを足してください。
Enumで全列定義しているのは、
わたしが枝番をふる以外のこともしたいからです。

Option Explicit

'---------------------------------------------------------------------------------------------------
' 定義
'---------------------------------------------------------------------------------------------------
Const DATA_START_ROW As Integer = 4    'データ開始行
Const LEVEL_NUM As Integer = 3         'レベルの階層

Private Enum eCOL    '列インデックス
    Level1 = 1
    Level2
    Level3
'    Level4
    項目Lv1
    項目Lv2
    項目Lv3
'    項目Lv4
    TRAILER
End Enum

'---------------------------------------------------------------------------------------------------
'【処 理 名】採番処理
'【処理概要】記述されている階層に応じて枝番をふる
'【引    数】なし
'【返 却 値】なし
'---------------------------------------------------------------------------------------------------
Public Sub 採番()
    Dim sh As Worksheet                        'ワークシートオブジェクト
    Dim items() As Variant                     'ワークシートデータ格納領域
    Dim serialNumber(LEVEL_NUM - 1) As Variant '採番作業領域
    Dim endRowIndex As Long                    'ワークシート末尾行
    Dim rowIndex As Long                       '行インデックス
    
    'ワークシートオブジェクト取得
    Set sh = ThisWorkbook.Worksheets("Sheet1")
    '末尾行取得
    endRowIndex = getEndRow(sh)
    For rowIndex = DATA_START_ROW To endRowIndex
        '配列に格納
        items = sh.Range(sh.Cells(rowIndex, eCOL.項目Lv1), _
                sh.Cells(rowIndex, eCOL.項目Lv1 + LEVEL_NUM - 1))
        '枝番配列生成
        Call createLevelArray(items, serialNumber)
        'ワークシートへ書き込み
        sh.Range(sh.Cells(rowIndex, eCOL.Level1), _
            sh.Cells(rowIndex, eCOL.Level1 + LEVEL_NUM - 1)) = serialNumber
    Next
    
    Set sh = Nothing
End Sub

'---------------------------------------------------------------------------------------------------
'【処 理 名】末尾行取得
'【処理概要】項目レベル11~項目レベル13の中で、最大の末尾行を取得する
'【引    数】[I]ByVal sh As Worksheet    ワークシートオブジェクト
'【返 却 値】末尾行数
'---------------------------------------------------------------------------------------------------
Private Function getEndRow(ByVal sh As Worksheet) As Long
    Dim endRowIndex As Long    '末尾行数取得領域
    Dim colIndex As Long       '列インデックス
    
    getEndRow = 0
    For colIndex = eCOL.項目Lv1 To eCOL.TRAILER - 1
        '末尾行取得
        endRowIndex = sh.Cells(Rows.Count, colIndex).End(xlUp).Row
        '今まで取得した末尾行より大きい場合は、その値を取得する
        If getEndRow < endRowIndex Then
            getEndRow = endRowIndex
        End If
    Next
End Function

'---------------------------------------------------------------------------------------------------
'【処 理 名】レベル取得
'【処理概要】何階層まで記載されているかを取得する
'【引    数】[I]items() As Variant    ワークシートの項目を格納した配列
'【返 却 値】レベル
'---------------------------------------------------------------------------------------------------
Private Function getLevel(items() As Variant) As Integer
    Dim index As Integer    '列インデックス
    
    getLevel = LEVEL_NUM
    '配列の要素数
    For index = 1 To LEVEL_NUM - 1
        'どこまで記載があるかで枝番のレベルを判定する
        If items(1, index) <> "" Then
            getLevel = index
            Exit Function
        End If
    Next index
End Function

'---------------------------------------------------------------------------------------------------
'【処 理 名】採番情報生成
'【処理概要】ワークシートに書き込むための採番情報を配列に格納する
'【引    数】[I]ByVal level As Integer               階層
'            [I/O]ByRef serialNumber() As Variant    採番情報格納配列
'【返 却 値】なし
'---------------------------------------------------------------------------------------------------
Private Sub createLevelArray(items() As Variant, ByRef serialNumber() As Variant)
    Dim level As Integer     '階層
    Dim branch As Integer    '現在の番号

    'レベル取得
    level = getLevel(items)
    '該当レベルの次の番号を取得する
    branch = IIf(serialNumber(level - 1) = "", 0, serialNumber(level - 1)) + 1
    '該当レベルより下の枝番はクリアする
    Call clearSerialNumberBranch(serialNumber, level)
    '該当レベルの番号を設定する
    serialNumber(level - 1) = branch
End Sub

'---------------------------------------------------------------------------------------------------
'【処 理 名】枝番クリア
'【処理概要】該当レベルより下の枝番はクリアする
'【引    数】[I/O]ByRef serialNumber() As Variant    採番情報格納配列
'            [I]ByVal level As Integer               階層
'【返 却 値】なし
'---------------------------------------------------------------------------------------------------
Private Sub clearSerialNumberBranch(ByRef serialNumber() As Variant, ByVal level As Integer)
    Dim index As Integer     '配列要素インデックス
    
    For index = level To UBound(serialNumber)
        serialNumber(index) = ""
    Next
End Sub

3 COMMENTS

Min

はじめまして。枝番作成マクロの件で教えてほしいことがコメントしました。

エクセルのA列~BD列まで入力されているのですが、eCOLの設定のところなどがよくわからないので教えてほしいです。また、セルが結合されている行があってもマクロは動きますか?
お手数をおかけしますがよろしくお願いします。

返信する
みすく参謀

Minさん

はじめまして!

eCOLは列インデックスとして使用しているので、
A列 = 1、B列 = 2、 C列 = 3・・・。
枝番の階層を4つ(1-1-1-1)にするなら、eCOLにLevel4、項目Lv4を増やします。
枝番の階層を5つ(1-1-1-1-1)にするなら、更にLevel5と項目Lv5を増やします。

Level4には4、Level5には5、項目Lv1も後ろにずれていくので、eCOLを設定することで、読み込む範囲を変えています。

セル結合については、どこを結合しているかによります。
枝番を書き込むセル、項目を書き込むセルを結合している場合は、同様にeCOLで調整していく必要があります。

うまく説明できていない気がするので、今度解説を詳しく書き直しますね。
またわからないことがあれば、遠慮なく聞いてください。

返信する

コメントを残す

メールアドレスが公開されることはありません。