『マクロの配列と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が〇の場合。(どちらかの条件満たしていれば、〇) 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