セルの塗りつぶされた色のRGBを求める方法

これ↓↓

Sub test_RGB()

    Dim myColor As Long
    Dim R, G, B
    
    myColor = Range("A1").Interior.Color
    
    R = myColor Mod 256
    G = Int(myColor / 256) Mod 256
    B = Int(myColor / 256 / 256)
    
    Debug.Print R, G, B

End Sub


微妙な色で塗りつぶされた色もこれで、RGBの数値を取ってこれます。
また、Interior.ColorIndexはエクセルのバージョンで挙動が異なるらしいです。
なのでRGB使いましょう!

備忘録でした。(^^)/~~~

複数のSheetに一括で同じ値を代入する方法

複数Sheetの同じセルに一括で値を代入する方法。

マニュアル操作では、Sheetを複数選択していれば同じセルに値が一気に代入するされます。これをVBAで記述すると以下のコードになります。

Sub Sheets_Select()
    
    Worksheets("Sheet7").Select
    Worksheets("Sheet4").Select False
    Worksheets("Sheet6").Select False
    
    Dim i
    For Each i In ActiveWindow.SelectedSheets
        i.Range("A1").Value = 67
        Debug.Print i.Name, i.Range("A1").Value
    Next
    
End Sub


処理結果↓↓
f:id:bimori466:20210526170810p:plain


一気にというところは怪しいですが、一応こうなりました。
備忘録でした。(^^)/~~~

複数のSheetに一括で同じ値を代入する方法

複数Sheetの同じセルに一括で値を代入する方法。

マニュアル操作では、Sheetを複数選択していれば同じセルに値が一気に代入するされます。これをVBAで記述すると以下のコードになります。

Sub Sheets_Select()
    
    Worksheets("Sheet7").Select
    Worksheets("Sheet4").Select False
    Worksheets("Sheet6").Select False
    
    Dim i
    For Each i In ActiveWindow.SelectedSheets
        i.Range("A1").Value = 67
        Debug.Print i.Name, i.Range("A1").Value
    Next
    
End Sub


処理結果↓↓
f:id:bimori466:20210526170810p:plain


一気にというところは怪しいですが、一応こうなりました。
備忘録でした。(^^)/~~~

指定した文字数の後に空白を入れる。

方法1

Sub stringTest()

    Dim myString As String * 18
    myString = "bimori"
    Debug.Print myString

End Sub


処理結果↓↓
f:id:bimori466:20210526140219p:plain


この場合、"bimori"以降18文字までは空白が入ります。
しかし、この方法では文字数が変わったときに対応できません。

方法2

Sub stringTest2()

    Dim myString As String
    myString = "bimori"
    myString = myString & Space(12)
    Debug.Print myString
    
End Sub


Space関数で、指定した数の空白を足します。


備忘録でした~。(^^)/~~~

セル内に斜線が入っているか判定して処理する。

f:id:bimori466:20210524125608p:plain

セル内に右下がり斜線が入っているか判定する処理。

セルの書式設定で斜めに斜線が入っている場合処理をする方法はないものか?と考えて、ググったらありました。
ここでは、セルA6に右斜め斜線(実線)が入っている場合に、赤でセルを塗りつぶす処理です。

Sub セルの斜線()

    If Range("A6").Borders(xlDiagonalDown).LineStyle = xlContinuous Then
       MsgBox "右斜め実線あり"
       Range("A6").Interior.Color = vbRed
    Else
       MsgBox "右斜め実線なし"
    End If


End Sub

処理結果

f:id:bimori466:20210524105927p:plain

赤色で塗りつぶされました。

こんな具合で、セルに罫線が引いてあるかで処理判定に使えます。

セル内に右上がり斜線が入っているか判定する処理。

Sub セルの斜線2()

    If Range("A6").Borders(xlDiagonalUp).LineStyle = xlContinuous Then
       MsgBox "右斜め実線あり"
       Range("A6").Interior.Color = vbRed
    Else
       MsgBox "右斜め実線なし"
    End If

End Sub


Borders(xlDiagonalDown) → Borders(xlDiagonalUp)に変更するだけです。


ではでは、この辺で(^^)/~~~

自作関数 正規表現を使って文字列付き連番に+1した値を取得する。続き。

f:id:bimori466:20210516060845p:plain

自作関数で-、/、空白の文字列付き連番を作る。

前回の記事で「文字列 + 数字」の文字列付き連番の取得方法について解説しました。
bimori466-1.hatenablog.com


今回は、「数字 + 英数字 + 数字」のような場合の文字列付き連番の取得方法について解説します。


1 閲覧対象者

文字列付き連番に+1した値がほしいとお困りの方。

2 得られる効果

文字列付き連番に対して+1した値を取得します。

(具体的データの例)
1AE-6-051/011277
1AO-6-033 004181
1AE-6-051/ 043090
1AP-5-160/010109
XPAS192-002584
XAPS055-033051
HAPS411-008042
1SA-6-037 /004943
UAPS028-032458
1AO-6-033 004185
2O-5-025/000440
1EA-6-051/ 043087
PDD-5-004/002984
1OA-5-432 002941

3 文字列付き連番の解析

前回のおさらいになりますが、2章に列挙した具体的なデータ例を分析すると末尾6桁が数字である」ということがわかります。
しかし、今回は「数字+文字列+数字」というパターンです。この場合前回作った正規表現のパターン「"(\D+)(\d+)"」ではうまく取れません。「1AE-6-051/011277」を例として、実際に実行してみると以下のような結果になります。

f:id:bimori466:20210518165840p:plain

結果として、AE-7が出力されました。当然ですね。文字列を頭から見て、数字以外の文字列は「AE-」、次にくる数字のみの文字列は「6」です。連番文字列が6なので+1して「AE-7」となります。ではどうすればいいでしょうか?

結論、-、/、空白で区切ればいいのです。
例の「1AE-6-051/011277」で言うと、「1AE-6-051/」と「011277」に分ければよいのです。
ではどうするか、コード解説します。

4 コードの解説

Sub 正規表現2()

    '正規表現の遅延バインディング
    Dim reg As Object: Set reg = CreateObject("VBScript.RegExp")
    
    '正規表現にマッチした文字列を格納するObject
    Dim matchString As Object, subMatchString As Object
    
    Dim targetString As String
    Dim targetStringプラス1 As String
    Dim strS As String
    Dim strN As String
    Dim separationStr As String
    Dim serchSrting As String
    Dim targetLen
    Dim resurutInstr1, resurutInstr2, resurutInstr3, rr
    Dim serchInstr1, serchInstr2, serchInstr3
    
    targetString = "1AE-6-051/011277"
    
    reg.Pattern = "(\D+)(\d+)"
        
    Set matchString = reg.Execute(targetString)(0)
    Set subMatchString = matchString.submatches
    
    
    'Pattern = "(\D+)(\d+)"がOKの処理
    strS = subMatchString(0)
    strN = subMatchString(1)
    
    
    If targetString = subMatchString.Item(0) & subMatchString.Item(1) Then
        targetLen = Len(strN)
        
        '連番作成
        strN = CLng(strN) + 1
        targetStringプラス1 = strS & Format$(strN, String$(targetLen, "0"))
        Debug.Print targetStringプラス1
    
    Else
        If InStr(1, targetString, "/") > 0 Then
                        
            '/より左側の文字列を取得
            reg.Pattern = "([^/]+(?:/))"
            Set matchString = reg.Execute(targetString)(0)
            strS = matchString.Value
            
            '/より右側の文字列を取得(/)を含むので、再度"(\D+)(\d+)"で数値を求める。
            reg.Pattern = "([/](\d+))"
            Set matchString = reg.Execute(targetString)(0)
            strN = matchString.Value
            
            reg.Pattern = "(\D+)(\d+)"
            Set matchString = reg.Execute(strN)(0)
            Set subMatchString = matchString.submatches
            separationStr = subMatchString.Item(0)
            strN = subMatchString.Item(1)
            targetLen = Len(strN)
            
            
            '連番作成
            strN = CLng(strN) + 1
            targetStringプラス1 = strS & Format$(strN, String$(targetLen, "0"))
            Debug.Print targetStringプラス1
        End If
    End If
    
End Sub


1  変数targetStringに「1AE-6-051/011277」を代入。
2  正規表現パターン”(\D+)(\d+)”でオブジェクト変数matchStringに文字列を取得する。
3  オブジェクト変数subMatchStringにオブジェクト変数matchStringのsubmatchesを代入する。
4  変数strSにオブジェクト変数subMatchString(0)を代入する。
   変数strNにオブジェクト変数subMatchString(1)を代入する
5  変数targetStringと変数strS&変数strNを比較する。

 ここからが、「/」の場合の処理
6  一致しない場合、正規表現パターン"([^/]+(?:/))"でオブジェクト変数matchStringに文字列を取得する(/より左側の文字列を取得)。変数strSに値を代入する。
7  正規表現パターン "([/](\d+))"でオブジェクト変数matchStringに文字列を取得する(/より右側の文字列を取得)。変数strNに値を代入する。
   補足:
    VBA正規表現では「後読み」ができないので、正確には「/を含む右側の文字列」を取得します。そのため、オブジェクト変数matchStringに対して、正規表現パターン"(\D+)(\d+)"で文字列を取得します。すると、「/」と「数字」に分かれた文字列がオブジェクト変数subMatchStringに取得できます。
8  オブジェクト変数subMatchString(1)の値を変数strNに代入する。
9  変数strNを+1する。
10 変数targetStringプラス1に、変数strS&変数strNを代入する。



1~10の工程を踏みます。長ったらしいですがこれで、「数字+文字列+数字」の連番を取ることができます。

処理結果↓↓
f:id:bimori466:20210518214641p:plain


1AE-6-051/011277 → 1AE-6-051/011278、ちゃんと連番になっていますね!

5 自作関数、-、/、空白の文字列付き連番のコード

今までのことを少し応用すれば、-、/、空白の文字列付き連番のコードが作成できます!

コードは以下の通り↓↓

Function myRegMachineNoNext(targetString As String)

    '正規表現の遅延バインディング
    Static reg As Object: Set reg = CreateObject("VBScript.RegExp")
    
    '正規表現にマッチした文字列を格納するObject
    Dim matchString As Object, subMatchString As Object
    
    Dim strS As String
    Dim strN As String
    Dim separationStr As String
    Dim serchSrting As String
    Dim targetLen
    Dim resurutInstr1, resurutInstr2, resurutInstr3, rr
    Dim serchInstr1, serchInstr2, serchInstr3
    
    reg.Pattern = "(\D+)(\d+)"
    
    strS = "": strN = "": separationStr = ""
        
        Set matchString = reg.Execute(targetString)(0)
        Set subMatchString = matchString.submatches
        
        
        If targetString = subMatchString.Item(0) & subMatchString.Item(1) Then
            'Pattern = "(\D+)(\d+)"がOKの処理
            strS = subMatchString(0)
            strN = subMatchString(1)
            
            targetLen = Len(strN)
            
            '連番作成
            strN = CLng(strN) + 1
            myRegMachineNoNext = strS & Format$(strN, String$(targetLen, "0"))
            
        Else
            'Pattern = "(\D+)(\d+)"がNGの処理(/、-、△)の処理。
            '-、/、△(空白)でどれが一番後ろの文字にでてくるか調べる。
            resurutInstr1 = 0: resurutInstr2 = 0: resurutInstr3 = 0
            rr = 1
            Do
                serchInstr1 = InStr(rr, targetString, "/")
                If serchInstr1 = 0 Then Exit Do
                resurutInstr1 = serchInstr1
                If serchInstr1 <> 0 Then rr = serchInstr1 + 1
            Loop Until serchInstr1 = 0
            If IsEmpty(resurutInstr1) Then resurutInstr1 = 0
            
            rr = 1
            Do
                serchInstr2 = InStr(rr, targetString, "-")
                If serchInstr2 = 0 Then Exit Do
                resurutInstr2 = serchInstr2
                If serchInstr2 <> 0 Then rr = serchInstr2 + 1
            Loop Until serchInstr2 = 0
            If IsEmpty(resurutInstr2) Then resurutInstr2 = 0
            
            rr = 1
             Do
                serchInstr3 = InStr(rr, targetString, " ")
                If serchInstr3 = 0 Then Exit Do
                resurutInstr3 = serchInstr3
                If serchInstr3 <> 0 Then rr = serchInstr3 + 1
            Loop Until serchInstr3 = 0
            If IsEmpty(resurutInstr3) Then resurutInstr3 = 0
            
            
            'serchSrting判定(一番後ろに出てくる文字)
            If resurutInstr1 > resurutInstr2 Then
                If resurutInstr3 > resurutInstr1 Then
                    serchSrting = " "
                Else
                    serchSrting = "/"
                End If
                
            Else
                If resurutInstr3 > resurutInstr2 Then
                    serchSrting = " "
                Else
                    serchSrting = "-"
                End If
            End If
            
            
            Select Case serchSrting
            
                Case Is = "/"
                    
                    If InStr(1, targetString, "/") > 0 Then
                        
                        '/より左側の文字列を取得
                        reg.Pattern = "([^/]+(?:/))"
                        Set matchString = reg.Execute(targetString)(0)
                        strS = matchString.Value
                        
                        '/より右側の文字列を取得(/)を含むので、再度"(\D+)(\d+)"で数値を求める。
                        reg.Pattern = "([/](\d+))"
                        Set matchString = reg.Execute(targetString)(0)
                        strN = matchString.Value
                        
                        reg.Pattern = "(\D+)(\d+)"
                        Set matchString = reg.Execute(strN)(0)
                        Set subMatchString = matchString.submatches
                        separationStr = subMatchString.Item(0)
                        strN = subMatchString.Item(1)
                        targetLen = Len(strN)
                        
                        
                        '連番作成
                        strN = CLng(strN) + 1
                        myRegMachineNoNext = strS & Format$(strN, String$(targetLen, "0"))
                    End If
                    
                Case Is = " "
                
                    If InStr(1, targetString, " ") > 0 Then
                        '△より左側の文字列を取得
                        reg.Pattern = "([^\s]+(?:\s))"
                        Set matchString = reg.Execute(targetString)(0)
                        strS = matchString.Value
                        
                        '\sより右側の文字列を取得(\s)を含むので、再度"(\D+)(\d+)"で数値を求める。
                        reg.Pattern = "([\s](\d+))"
                        Set matchString = reg.Execute(targetString)(0)
                        strN = matchString.Value
                        
                        reg.Pattern = "(\D+)(\d+)"
                        Set matchString = reg.Execute(strN)(0)
                        Set subMatchString = matchString.submatches
                        separationStr = subMatchString.Item(0)
                        strN = subMatchString.Item(1)
                        targetLen = Len(strN)
                       
                        
                        '連番作成
                        strN = CLng(strN) + 1
                        myRegMachineNoNext = strS & Format$(strN, String$(targetLen, "0"))
                    End If
                    
                Case Is = "-"
                
                    If InStr(1, targetString, "-") > 0 Then
                        
                        '-より左側の文字列を取得
                        reg.Pattern = "([^-]+(?:-))"
                        Set matchString = reg.Execute(targetString)(0)
                        strS = matchString.Value
                        
                        '-より右側の文字列を取得(-)を含むので、再度"(\D+)(\d+)"で数値を求める。
                        reg.Pattern = "([-](\d+))"
                        Set matchString = reg.Execute(targetString)(0)
                        strN = matchString.Value
                        
                        reg.Pattern = "(\D+)(\d+)"
                        Set matchString = reg.Execute(strN)(0)
                        Set subMatchString = matchString.submatches
                        separationStr = subMatchString.Item(0)
                        strN = subMatchString.Item(1)
                        targetLen = Len(strN)
                        
                        
                        '連番作成
                        strN = CLng(strN) + 1
                        myRegMachineNoNext = strS & Format$(strN, String$(targetLen, "0"))
                    End If
                    
                    
            End Select
        End If

End Function


処理を加えた点としては、-(ハイフン)、/(スラッシュ)、” ”(半角空白)の3つの内で一番遅くでできた文字列を正規表現パターンとします。それくらいですね!

ワークシート上の実行結果↓↓

f:id:bimori466:20210518215443p:plain


文字列付き連番が取得できていますね!以上です。

6 感想

実はこの自作関数は完璧ではありません。そう、末尾に-(ハイフン)、/(スラッシュ)、空白がきたら処理できません。空白はRtrimで対応はできますが、完璧な文字列付き連番にするにはもう少し工夫が必要ですね。しかしながら、大方このパターンで私の業務は問題なかったです。

いかがだったでしょうか。正規表現というとLinuxPowerShellなどをイメージしますが、VBAでも割と使えるんですね。
ExcelVBA奥が深い。しかし、もっとスマートな書き方がある気はしています。


ではでは、この辺で(^^)/~~~

自作関数 正規表現を使って文字列付き連番に+1した値を取得する。

f:id:bimori466:20210516060845p:plain

エクセルVBA正規表現を活用

お仕事で「文字列付き連番」に遭遇しました。
文字列付き連番って、変数に入れて+1するだけでは連番は取れないのです。
今回は、文字列+数字、-(ハイフン)、/(スラッシュ)、” ”(半角空白)この4パターンの文字列付き連番に+1した値を取得するFunctionを作成してみました。
正規表現をよくわかってませんが、なんとかなりましたw

1 閲覧対象者

文字列付き連番に+1した値がほしいとお困りの方。

2 得られる効果

文字列付き連番に対して+1した値を取得します。

(具体的データの例)
ABB-F 074984
ASS-E-004348
AFJ-E/096888
1AE-6-051/011277
1AO-6-033 004181
1AE-6-051/ 043090
1AP-5-160/010109
XPAS192-002584
XAPS055-033051
HAPS411-008042
1SA-6-037 /004943
UAPS028-032458
1AO-6-033 004185
2O-5-025/000440
1EA-6-051/ 043087
PDD-5-004/002984
1OA-5-432 002941


3 文字列付き連番の解析

2章に列挙した具体的なデータ例を分析してみましょう。そうすると、どうやら「末尾6桁が数字である」ということがわかります。
ただし、「文字列+数字」という単純な組み合わせだけでなく、「数字+文字列+数字」というパターンもあります。
では実際に、文字列付き連番を取得するコードを書いてみましょう!

4 VBA正規表現を使う方法

遅延バインディングの例

 '正規表現の遅延バインディング
    Static reg As Object: Set reg = CreateObject("VBScript.RegExp")
    
    '正規表現にマッチした文字列を格納するObject
    Dim matchString As Object, subMatchString As Object


実行時バインディングの設定方法は、ここでは割愛します。
とりあえず、これで正規表現を使う準備は整いました。実際に正規表現を使ってみましょう!

5 「文字列+数字」の場合の連番を取得する

「文字列+数字」このパターンが一番多く、簡単だと思います。
具体的な例で言うと、
ABB-F 074984
ASS-E-004348
AFJ-E/096888

この3パターンです。この3つを例に正規表現の使い方を見てみましょう。


まずは「ABB-F 074984」のパターンを使って説明します。
変数targetStringに"ABB-F 074984"を直代入しています。
では、正規表現の使い方を説明します。

Sub 正規表現1()

    '正規表現の遅延バインディング
    Dim reg As Object: Set reg = CreateObject("VBScript.RegExp")
    
    '正規表現にマッチした文字列を格納するObject
    Dim matchString As Object, subMatchString As Object
    
    Dim targetString As String
    Dim targetStringプラス1 As String
    Dim strS As String
    Dim strN As String
    Dim separationStr As String
    Dim serchSrting As String
    Dim targetLen
    Dim resurutInstr1, resurutInstr2, resurutInstr3, rr
    Dim serchInstr1, serchInstr2, serchInstr3
    
    targetString = "ABB-F 074984"
    
    reg.Pattern = "(\D+)(\d+)"
        
    Set matchString = reg.Execute(targetString)(0)
    Set subMatchString = matchString.submatches
    
    'Pattern = "(\D+)(\d+)"がOKの処理
    strS = subMatchString(0)
    strN = subMatchString.Item(1)
    
    targetLen = Len(strN)
    
    '連番作成
    strN = CLng(strN) + 1
    targetStringプラス1 = strS & Format$(strN, String$(targetLen, "0"))
    Debug.Print targetStringプラス1
    
End Sub

コードの説明

1 正規表現の遅延バインディング
  Dim reg As Object: Set reg = CreateObject("VBScript.RegExp")

2 正規表現のマッチングパターンを選択する。
  reg.Pattern = "(\D+)(\d+)"

  補足:
  "(\D+)(\d+)"中の「\」は「¥」でも構いません。ここでは「\」で統一します。
  「\D」とは、任意の数値以外の文字を取得します。
  「\d」とは、任意の数値を取得します。
  「(\D)」の「()」はパターンのグループ化です。私の理解では、subMatchesで使うためのものと理解しています。詳細は後ほど。

3 オブジェクト変数matchStringにreg.Patternで設定した正規表現の取得を実行する。
  Set matchString = reg.Execute(targetString)(0)

4 オブジェクト変数matchStringのsubmatchesに格納された配列を、オブジェクト変数subMatchStringに格納する。
  Set subMatchString = matchString.submatches

  補足:
  今回の文字列「ABB-F 074984」で数字以外の文字列(\D)は「ABB-F 」です。また、数字の文字列(\d)は「074984」です。
  この二つが、オブジェクト変数matchString.submatchesに配列として格納されます。

5 変数strSにmatchString.submatches(0)を格納します(ABB-F )。また、変数strNにmatchString.submatches(1)を格納します(074984)。

6 連番を取得するため、変数strNに+1をします。
  strN = CLng(strN) + 1
  
  補足:
  変数strNには「074984」が文字列として格納されています。文字列の数字を結合すると先頭の「0」は無くなってしまします。そのため、Format関数を使っています。

Executeの挙動を確認する。

実際にExecuteしたときのデータの取れ方をウォッチウィンドウで確認してみましょう。
そうすると、以下の画像の通り↓↓
f:id:bimori466:20210516075308p:plain


matchStringのsubmatchesに、数値以外のデータと数値のデータが取得できていることがわかります。これがおそらくグループ化「()でくくる」意味なのだと思います。
後は、変数strS、変数strNにmatchString.submatches(0)、matchString.submatches(1)の値を代入します。

*注Item1となっていますが、初期値はsubmatches(0)です。

実行結果

「ABB-F 074984」の連番「ABB-F 074985」が取得できていますね!
f:id:bimori466:20210516075804p:plain

6 感想

多くの文字列付き連番は、「reg.Pattern = "(\D+)(\d+)"」この正規表現で解決するのではないかと思っております。
しかしながら、「数字+文字列+数字」この場合では機能しません。
記事が長くなったので、文字列+数字、-(ハイフン)、/(スラッシュ)、” ”(半角空白)この3パターンの文字列付き連番の取得の仕方は後述します。


追加記事を書きました。↓↓
bimori466-1.hatenablog.com



ではでは、この辺で(^^)/~~~