Excel (VBA)

Excel VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(指定なし : 指定なし)
文字検索について
投稿日時: 22/10/27 10:31:53
投稿者: vaioyuki

いつもお世話になっております。
 
現在下記で対象文字を検索し、対照するセルに色を付けています。
 

Sub 検索() '検索対象:アクティブシート
    Dim varArray   As Variant
    Dim v          As Variant
    Dim strAddress As String
    Dim rngFnd     As Range
    Dim rngUni     As Range
    Dim cell As Range
    
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
    
    varArray = Array( "ワード", ) '検索文字列

'正解例 Word
                        
    For Each v In varArray
        Set rngFnd = Cells.Find(What:=v, LookAt:=xlPart, MatchCase:=True) '
        If Not rngFnd Is Nothing Then
            strAddress = rngFnd.Address '最初に検索一致したセルの番地格納
            If rngUni Is Nothing Then Set rngUni = rngFnd
            Do
                Set rngUni = Union(rngUni, rngFnd)  'セルを集合
                Set rngFnd = Cells.FindNext(rngFnd) '次の一致セルを検索
            Loop Until strAddress = rngFnd.Address  'セルのアドレスが一致したらループを抜ける
        End If
    Next
    
    If Not rngUni Is Nothing Then rngUni.Interior.ColorIndex = 6 '検索一致セルの選択
    
    Application.ScreenUpdating = True
    Application.Calculation = xlCalculationAutomatic

'MsgBox "処理終了"

End Sub

 
実際にはもっとたくさんの文字検索を行ってるのですが、困っているのはこの「ワード」です。
ワードは「Word」にしたいためにまず検索を行っているのですが、この際、「パスワード」の「ワード」にも反応してセルに色が付きます。
 
こういった場合はどのように処理をすればいいのか知恵をお貸しください。
よろしくお願いします。

回答
投稿日時: 22/10/27 11:20:17
投稿者: WinArrow
投稿者のウェブサイトに移動

ヒント
 

Dim KrngFnd As String
    
    KrngFnd = rngFnd.Value
    If InStr(KrngFnd, "ワード") > 2 Then
        If Mid(KrngFnd, InStr(KrngFnd, "ワード") - 2, 5) = "パスワード" Then
            MsgBox "Ok"
        End If
    End If

回答
投稿日時: 22/10/27 11:20:56
投稿者: simple

ワードは「Word」にしたいためにまず検索を行っているのですが、
この際、「パスワード」の「ワード」にも反応してセルに色が付きます。
 
今はワードを含むものを検索しているが、セルが「ワード」に一致したものだけ検索したい
ということですか?それなら、LookAt:=xlWhole にするわけですが。
そういう話でなければ、もっと詳しく、論理的な表現で条件を書いて下さい。

投稿日時: 22/10/27 11:35:28
投稿者: vaioyuki

ありがとうございます。
 
上記にも書きましたが、他にも検索文字がたくさんありまして、
今は「パスワード」に引っかかってセルが黄色くなるのは「パスワードね」と思ってスルーしていたのですが、
これが「Windows」の文字表記エラーとして「Window」の「s」だけが未入力を見つけたい場合も「Window」で検索すると「Windows」が引っかかってくるのでは?と思い、これを回避するものがあればと思い質問しました。
 
「ワード」に関しては他にも「word」「WORD」なども検索対象にしています。
その他の文字としては(こちらは問題ないのですが)「iPAD」「IPAD」「office」「オフィス」「excel」「EXCEL」「エクセル」などもあります。

回答
投稿日時: 22/10/27 11:42:07
投稿者: sk

引用:
ワードは「Word」にしたいためにまず検索を行っているのですが、
この際、「パスワード」の「ワード」にも反応してセルに色が付きます。

--------------------------------------------------------
 
"パスワードを入力して下さい"
 
-> パスワード / を / 入力 / して / 下さい
 
-> False
 
--------------------------------------------------------
 
"ネット上で今このワードがバズっています"
 
-> ネット上 / で / 今 / この / ワード / が / バズ / って / います
 
-> True
 
--------------------------------------------------------
 
といったように、文章に含まれる文字列を(日本語の)単語単位に
分解し、検索文字列と完全一致する単語が含まれているか否かを
判別したい、ということでしょうか。

投稿日時: 22/10/27 11:53:01
投稿者: vaioyuki

sk さんの引用:

といったように、文章に含まれる文字列を(日本語の)単語単位に
分解し、検索文字列と完全一致する単語が含まれているか否かを
判別したい、ということでしょうか。

 
あ、そうですそうです!!
「ワードで書類を作成した。」のように入力しているセルを見つけたいというものです。
 
言葉足らずで申し訳ありません。

回答
投稿日時: 22/10/27 11:58:11
投稿者: Suzu

とりあえず、Findメソッドは、「ホーム」-「編集」の 検索と選択 「検索」で表示される
「検索と置換」の 検索 を VBA で実行する時の メソッドです。
  
検索には
・大文字と小文字を区別する
・セル内容が完全に同一であるものを検索する
・半角と全角を区別する
 等 の オプションが存在します。
  
手動検索で、それらの条件を試してみて
希望の検索結果が得られたら、マクロの記録を使い、その条件の検索の コードを確認してみましょう。
  
どんなオプションを使えるか等はヘルプを確認してみましょう。
  
Range.Find メソッド (Excel)
https://learn.microsoft.com/ja-jp/office/vba/api/excel.range.find
 
 
今回の様に、検索対象に対し、セルの背景色を一括で色を変えるには
「ホーム」-「編集」の 検索と選択 「検索」で表示される「置換」の方を使い
置換後の文字列の右側の書式で、塗りつぶしを使えば良いです。

回答
投稿日時: 22/10/27 13:48:16
投稿者: simple

Excelから利用できるトークナイザーとしては、
(1)WordのRangeオブジェクトのWordsプロパティの利用が手ごろでしょうか。
(2)形態素解析ツールのMecabをVBAから使うこともできたと思います。
ネットで調べてみて下さい。
# 出かけますので少しの間、アクセスできません。

回答
投稿日時: 22/10/27 14:36:22
投稿者: sk

引用:
Set rngFnd = Cells.Find(What:=v, LookAt:=xlPart, MatchCase:=True)

引用:
「ワード」に関しては他にも「word」「WORD」なども検索対象にしています。
その他の文字としては(こちらは問題ないのですが)「iPAD」「IPAD」
「office」「オフィス」「excel」「EXCEL」「エクセル」などもあります。

とりあえずバイナリ比較方式で検索する場合。
 
(標準モジュール)
-------------------------------------------------------------------
Sub 検索() '検索対象:アクティブシート
    Dim varArray As Variant
    Dim v As Variant
    Dim strAddress As String
    Dim rngFnd As Range
    Dim rngUni As Range
    Dim cell As Range
     
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
     
    '全てのセルの塗りつぶしを「色なし」に
    Cells.Interior.ColorIndex = xlColorIndexNone
     
    varArray = Array("ワード", "エクセル") '検索文字列を1次元配列で指定
 
    Dim shp As Excel.Shape
    Dim txr As Office.TextRange2
     
    '空のテキストボックスを一時的に作成する
    Set shp = ActiveSheet.Shapes.AddTextbox(msoTextOrientationHorizontal, 0, 0, 100, 100)
    '非表示化
    shp.Visible = False
    'テキストボックスの文字列範囲の参照
    Set txr = shp.TextFrame2.TextRange
 
    For Each v In varArray
        'まず部分一致するセルを検索する
        Set rngFnd = Cells.Find(What:=v, LookAt:=xlPart, MatchCase:=True)
        'ヒットした場合
        If Not rngFnd Is Nothing Then
            strAddress = rngFnd.Address '最初に検索一致したセルの番地格納
            Do
                'ヒットしたセルの値をテキストボックスに代入する
                txr.Text = rngFnd.Value
                '単語レベルでの文字列検索でマッチした場合
                If FindWordInTextRange(shp.TextFrame2.TextRange, CStr(v)) = True Then
                    If rngUni Is Nothing Then
                        Set rngUni = rngFnd
                    Else
                        Set rngUni = Union(rngUni, rngFnd) 'セルを集合
                    End If
                End If
                Set rngFnd = Cells.FindNext(rngFnd) '次の一致セルを検索
            Loop Until strAddress = rngFnd.Address 'セルのアドレスが一致したらループを抜ける
        End If
    Next
     
    If Not rngUni Is Nothing Then rngUni.Interior.ColorIndex = 6 '検索一致セルの選択
     
    '作成したテキストボックスの後始末
    Set txr = Nothing
    shp.Delete
    Set shp = Nothing
     
    Application.ScreenUpdating = True
    Application.Calculation = xlCalculationAutomatic
 
'MsgBox "処理終了"
 
End Sub
 
'TextRange2 オブジェクトの機能を利用して単語レベルでの文字列検索を行なう関数
Private Function FindWordInTextRange(TextRange As Office.TextRange2, Keyword As String) As Boolean
 
    'ヒットしなければ False を返す
    FindWordInTextRange = False
 
    'キーワードが空文字列なら抜ける
    If Keyword = "" Then
        Exit Function
    End If
 
    Dim lngWordCount As Long
    Dim strJoinedWords As String
     
    '単語連結文字列の初期化
    strJoinedWords = ""
     
    With TextRange
        'テキストボックスの文字列範囲に含まれる単語の数だけループ
        For lngWordCount = 1 To .Words.Count
            'n個目の単語をイミディエイトウィンドウに出力(デバッグ用)
            Debug.Print .Words(lngWordCount)
            '前方一致し続ける限り単語を追記する
            strJoinedWords = strJoinedWords & .Words(lngWordCount)
            'キーワードと前方一致する場合
            If Keyword Like (strJoinedWords & "*") Then
                'かつバイナリ比較方式で完全に一致する場合
                If StrComp(Keyword, strJoinedWords, vbBinaryCompare) = 0 Then
                    'Trueを返してプロシージャを抜ける
                    FindWordInTextRange = True
                    Exit Function
                End If
            Else
                '前方一致しなければ単語連結文字列を初期化
                strJoinedWords = ""
            End If
        Next
    End With
 
End Function
-------------------------------------------------------------------
 
但し、日本語の文章(特に人名、地名、固有名詞、スラングが
含まれる文章、助詞が省略された文章など)を対象とした
識別の精度は、英文のそれよりも遙かに落ちるはず。
 
例えば「去年の流行語大賞の発表は12月1日でした」という文章から
「流行語」という単語を検索する場合、「流行語大賞」という文字列は
1つの固有名詞ではなく「流行語」と「大賞」という2つの名詞に分けられ、
ヒットの対象となります。

回答
投稿日時: 22/10/27 16:54:15
投稿者: sk

sk さんの引用:
英文のそれ

英文にも対応するなら、次のように修正した方がよさげ。
 
sk さんの引用:
'キーワードと前方一致する場合
If Keyword Like (strJoinedWords & "*") Then
    'かつバイナリ比較方式で完全に一致する場合
    If StrComp(Keyword, strJoinedWords, vbBinaryCompare) = 0 Then

'キーワードと前方一致する場合
If Trim(Keyword) Like (Trim(strJoinedWords) & "*") Then
    'かつバイナリ比較方式で完全に一致する場合
    If StrComp(Trim(Keyword), Trim(strJoinedWords), vbBinaryCompare) = 0 Then

投稿日時: 22/11/04 14:01:18
投稿者: vaioyuki

お返事が遅れて申し訳ありません。
諸事情で隔離されておりました。(お察しください。。。)
 
仕事は休んでおりますが今日から復帰して再度、確認して試してみます。
色々ありがとうございました。