[[20231019072138]] 『マクロの配列とIFの組み合わせ』(勉強) ページの最後に飛ぶ

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

 

『マクロの配列とIFの組み合わせ』(勉強)

表題の件、教えてください。下記リストがあります。

  A       B
 1  検索1 検索2
 2  A	  a-excel-ng
 3	  aa-aa-vba
 4  B	  ng-yay-vv
 5  A	  aa-yy-yy
 6  B	  vba-yay-a
 7  C	  aa-yy-yy
 8  A	  ng-yay-excel

これを条件分けして、D列判定1, E列判定2に結果を入力したい。
条件は…
下記の場合、D列:判定1に〇を入力
・検索2の文字の中に、excel 、vbaという文字が入っていたらD列に〇を付けたい。ただし、ngという文字も含まれていたら〇にしたくない。(B2セルは、excelが入っているが、ngも入っているため〇にしない。)

下記の場合、E列:判定2に”対象"と入力
・検索1がAか空欄の場合、もしくは、判定1が〇の場合。(どちらかの条件満たしていれば、〇)

<Outputはこうなりたい>

    D      E
 1  判定1  判定2
 2     	   対象
 3  〇	   対象
 4	
 5	  対象
 6  〇	   対象
 7
 8         対象

判定1に〇を付けるマクロを考えてみたのですが、うまくいきません。
判定2も同じようなイメージでやりたい。

分からないところ
1.ifとorとandの書き方や <>0 の部分とか分からない。( )で囲わないといけない部分があるのか?デバックで1行ずつ試すと、正しく処理されていないと思われる。
2.結果をはき出す部分が配列の中に入ってしまっているからか、全て〇になってしまう。
3. 2については、今Range("D2:D8")と直接指定しているが合っているか?
4. For i = 2 To UBound(A, 1) の 2 Toの部分は項目名があるから2にしたがその理解でいいか?

Sub test1()

  Dim A
  A = Range("A1:B8").Value

  For i = 2 To UBound(A, 1)
'  If InStr(A(i, 2), "excel") > 0 Then
    If InStr(A(i, 2), "excel") > 0 Or InStr(A(i, 2), "vba") > 0 And InStr(A(i, 2), "ng") <> 0 Then
        Range("D2:D8").Value = "〇"
    End If
  Next

End Sub

< 使用 Excel:Microsoft365、使用 OS:Windows10 >


時間なので確認だけで申し訳ないです。
InStr(A(i, 2), "ng")だと、vba-test-orange では○が付きませんが問題ありませんか?

(anon) 2023/10/19(木) 08:10:48


ご確認ありがとうございます。
InStr(A(i, 2), "ng")だと、vba-test-orange では○が付きませんが問題ありませんか? この場合は、○にしたいです。vbaが入っていてngの文字がないので。

よろしくお願いします。
(勉強) 2023/10/19(木) 08:16:21


 まず、単語として、文字列を正しく判別するために、
 どうしたらいいか考えます。

 提示データから、共通性を見出し、
 単語とするならば、-(ハイフン)で区切られているものが
 それとなるので、
 Split関数で、-(ハイフン)で区切った文字列の配列を作ります。
 その各単語と比較するといった流れでしょうか。

 大切なのは、コードの書き方ではなく、
 自身が機械となり、判定するならどうするか、を考えることが大事で、
 その考えをコードにすることです。

(tkit) 2023/10/19(木) 08:51:22


tkit様
ありがとうございます。
そうですね。大変勉強になります。
すみません、事例ではハイフンを使用していますが、実際には区分ける規則的なものがありません。
空白スペースだったりハイフンだったり色々。かつ、全くの空欄の場合もある。
関数でやろうとすると、count ifでワイルドカード使うことになると思いますが、それと同じことをマクロでできないかと思って質問させていただきました。
(勉強) 2023/10/19(木) 08:59:39

 Range("D2:D8").Value = "〇"
 としているので、この7つのセル全部に○が入ります。
 変数iに応じて1つのセルだけに書き込むようにしないといけないです。

 orangeにngが含まれないんですか

 "vba-test-orange" の前後に - 付けて "-vba-test-orange-" と "-ng-" を比較するといいですよ 

 と思ったら、
 >空白スペースだったりハイフンだったり色々
 私には無理です1...
(´・ω・`) 2023/10/19(木) 09:02:06

空白スペースだったりハイフンだったり色々
  
    ↑ を

全て調べて[少しでもあれば規則性を見出だして^^;なければアナログ
USE EYE & HAND。。。( ̄▽ ̄)]
ユニークなキーを作ればどうなのでせうね。だめっすかね。。。m(__)m
(隠居Z) 2023/10/19(木) 09:43:51


みなさま
ありがとうございます。規則性、調べてみます。
あと、InStr(A(i, 2), "ng") <> 0の書き方はおかしいですね。
InStr(A(i, 2), "ng") = 0 ですね、、、

結果のはき出しは、cells(i,4)とかにすれば良いのですね。
色々参考情報、ありがとうございます。
(勉強) 2023/10/19(木) 09:56:23


 >関数でやろうとすると、count ifでワイルドカード使うことになると思いますが、
 >それと同じことをマクロでできないかと思って質問させていただきました。

 関数でやっても、anonさんの指摘と同じことになりますよ。

 >空白スペースだったりハイフンだったり色々。かつ、全くの空欄の場合もある。

 色々であきらめずに、何かを全て拾って、それぞれで比較するしかないですかね。

(tkit) 2023/10/19(木) 10:09:23


tkit様
ありがとうございます。
まずは条件を整理して、検討してみたいと思います。
(勉強) 2023/10/19(木) 10:20:46

すでにお気付きかと思いますが、
InStr関数は検索対象の文字列に検索値が含まれていたら、その開始位置を返します。

 Sub test()
    Debug.Print InStr("ng", "ng")
    Debug.Print InStr("orange", "ng")
    Debug.Print InStr("-vba-test-orange-", "-ng-")
 End Sub

 実行結果
 1 
 4 
 0 

InStr関数で単語ごとに完全一致を行うには、
(´・ω・`)さんが挙げられている例の様に工夫が必要です。
(anon) 2023/10/19(木) 19:46:06


 Sub test1()
    Dim r As Range, v
    Dim i As Long
    Dim delm, e
    Dim tmp As String, s
    Dim m1, m2, m3

    delm = Array("-", ",", "/", ".")

    Set r = Range("A1").CurrentRegion.Resize(, 5)
    Set r = Intersect(r, r.Offset(1))
    r.Columns("D:E").ClearContents
    v = r.Value

    For i = 1 To UBound(v)
        tmp = v(i, 2)
        For Each e In delm
            tmp = Replace(tmp, e, " ")
        Next
        s = Split(tmp)
        m1 = Application.Match("excel", s, 0)
        m2 = Application.Match("vba", s, 0)
        m3 = Application.Match("ng", s, 0)

        If (IsNumeric(m1) Or IsNumeric(m2)) And IsError(m3) Then
            v(i, 4) = "〇"
            v(i, 5) = "対象"
        ElseIf v(i, 1) = "" Or v(i, 1) = "A" Then
            v(i, 5) = "対象"
        End If
    Next

    r.Value = v

 End Sub
(マナ) 2023/10/19(木) 21:36:34

書き溜めている間に被ってしまいましたが投稿しておきます。
 -----------------------------------------------------

既に必要なアドバイスは頂いていると思いますが何点か。

■1
↓の狙いは何ですか?

 A = Range("A1:B8").Value

そんなに難しくせずとも【1行ずつ】処理していけば済む話なのではありませんか?
また、既に指摘がありますが↓だとマズイですよね。

 Range("D2:D8").Value = "〇"

■2
(´・ω・`)さん指摘のようなケースが無い(特定の文字が含まれているかどうかで判定すればよい)場合、上記を踏まえて↓のように考えればよいと思います。

 1. 2〜B列最終行まで、1行ずつ見ていき
 
 2.  B列の値を取得して"excel"か"vba"が含まれているか判定する
 3. ↑が真なら"ng"が含まれないか判定する
 4.   「1.」「2.」がいずれも真ならD列に"〇"を書き込む

 5. 最終行まで繰り返し処理したらおしまい

これをコード化してみるとこんな感じです。

 ※完成品プレゼントの意図はありません。
  採用される場合は【ステップ実行】等で研究の上、理解されてから必要な部分のみご自身のコードに組み込んでください。

    Sub 研究用1()
        Dim 行 As Long

        With ActiveSheet
            For 行 = 2 To .Cells(.Rows.Count, "B").End(xlUp).Row
                If InStr(.Cells(行, "B").Value, "excel") > 0 Or InStr(.Cells(行, "B").Value, "vba") > 0 Then
                    If InStr(.Cells(行, "B").Value, "ng") = 0 Then
                        .Cells(行, "D").Value = "〇"
                    End If
                End If
            Next 行
        End With
    End Sub

■3
また、上記の「2.」「3.」を数式で考えると、例えば↓のようにすれば目的は達成できると思います

 D2セル =IF(AND(SUM(COUNTIF(B2,{"*excel*","*vba*"})),COUNTIF(B2,"*ng*")=0),"〇","")

■4
>判定2も同じようなイメージでやりたい。
上記を踏まえると、マクロでも実現可能ですが、多分数式のほうが簡単だと思います。
マクロの勉強を兼ねているという話であれば、まずはトライして詰まったら、具体的なコードを提示して質問されるとよいでしょう

■5
さて、上記までは【単語で判定する必要が無い場合】の話です。
単語として判断する必要がある場合は↓も相まって手当てすることが多くなります。

 >実際には区分ける規則的なものがありません。
 >空白スペースだったりハイフンだったり色々。

一応、処理の流れを整理すると、たとえば↓のような処理をすればよいと思います。

 0. 区切文字として使っていそうな文字をピックアップしておく

 1. 2〜B列最終行まで、1行ずつ見ていき

 2. B列の値を取得する
 3. ↑の区切文字をReplace関数を使って1種類に統一する
 4. ↑をSplit関数を使って、配列として取得する
 5. Filter関数を使って配列に"excel"が含まれているか判定する
 6. Filter関数を使って配列に"vba"が含まれているか判定する
 7. Filter関数を使って配列に"ng"が含まれていないか判定する
 8. 5〜7がいずれも真なら、D列に"〇"を書き込む

 9. 最終行まで繰り返し処理したらおしまい

こちらも研究用資料としてコードを提示しておきます。

 ※研究すればわかるとおり、【区切文字候補】がピックアップできるかどうかが肝になるとおもいます。

    Sub 研究用2()
        Dim 行 As Long
        Dim 区切文字 As Variant, 区切文字候補 As Variant
        Dim 配列 As Variant, buf As String

        区切文字候補 = Array("-", "−", " ", " ", "/", ",", "、")

        With ActiveSheet
            For 行 = 2 To .Cells(.Rows.Count, "B").End(xlUp).Row
                buf = .Cells(行, "B").Value
                For Each 区切文字 In 区切文字候補
                    buf = Replace(buf, 区切文字, vbTab)
                Next

                配列 = Split(buf, vbTab)
                If UBound(Filter(配列, "excel")) >= 0 Or UBound(Filter(配列, "vba")) >= 0 Then
                    If UBound(Filter(配列, "ng")) < 0 Then
                        .Cells(行, "D").Value = "〇"
                    End If
                End If
            Next

        End With
    End Sub

(もこな2) 2023/10/19(木) 23:26:49


 正規表現を使った例(単語境界を利用)を示します。
 たぶんなじみがないと思いますので、質問者さんにはスキップいただいて結構です。
 全体の枠組みは、マナさんの提示されたものを使わせていただきました。

 Dim re        As Object
 Sub test()
     Dim r     As Range, v
     Dim s     As String
     Dim i     As Long

     Set re = CreateObject("VBScript.RegExp")
     re.IgnoreCase = True        '大文字小文字を区分しない

     Set r = Range("A1").CurrentRegion.Resize(, 5)
     Set r = Intersect(r, r.Offset(1))
     r.Columns("D:E").ClearContents
     v = r.Value
     For i = 1 To UBound(v)
         s = v(i, 2)
         '"excel"または"vba"という要素を含み、かつ"ng"という要素を含まない。
         ' (要素ごとの判定は完全一致)
         If (myTest(s, "excel") Or myTest(s, "vba")) And Not myTest(s, "ng") Then
             v(i, 4) = "〇"
             v(i, 5) = "対象"
         ElseIf v(i, 1) = "" Or v(i, 1) = "A" Then
             v(i, 5) = "対象"
         End If
     Next
     r.Value = v
 End Sub

 Function myTest(s As String, pattern As String) As Boolean
     Dim pat As String
     pat = "\b" & pattern & "\b"  ' "\b"は単語境界を表す
     re.pattern = pat
     myTest = re.test(s)
 End Function

(xyz) 2023/10/20(金) 05:50:16


コメント返信:

[ 一覧(最新更新順) ]


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