Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


9848 / 13646 ツリー ←次へ | 前へ→

【25090】検索→削除 いづみ 05/5/19(木) 21:46 質問[未読]
【25114】Re:検索→削除 ponpon 05/5/20(金) 14:45 回答[未読]
【25136】Re:検索→削除 いづみ 05/5/21(土) 0:03 質問[未読]
【25137】Re:検索→削除 ponpon 05/5/21(土) 13:07 回答[未読]
【25138】Re:検索→削除 kobasan 05/5/21(土) 15:17 発言[未読]
【25141】Re:検索→削除 ponpon 05/5/21(土) 21:42 発言[未読]
【25145】Re:検索→削除 ちゃっぴ 05/5/22(日) 13:13 回答[未読]
【25146】Re:検索→削除 いづみ 05/5/22(日) 15:00 質問[未読]
【25151】Re:検索→削除 ちゃっぴ 05/5/22(日) 22:13 回答[未読]

【25090】検索→削除
質問  いづみ  - 05/5/19(木) 21:46 -

引用なし
パスワード
   初めまして。こんばんわ。

sheet1に下記のようなデータがあります。

   A  B  C  D  E  
1
2
3
4  番号 ワード 個数 単価 合計 
5   2  電話  1  100  100
6  5 電話に  2  100  200
7  8 時計が  1  200  200

sheet2 に
  A
1 ワード
2 電話
3 時計

とあります。ともに行数は100ぐらいです。

sheet1のB列のワードでsheet2のA列の文字を含むものだけを
残してあとは行ごと削除したいです。(なので"電話に"も残したいです)
sheet2は月1回程の変更ですがsheet1は1日ごとにsheetが増えます。
自動記録をしてみたのですが、その後どのように変更したら
うまくいくのかわかりません。
どなたかお教えいただければありがたいです。

よろしくお願いいたします。

【25114】Re:検索→削除
回答  ponpon E-MAIL  - 05/5/20(金) 14:45 -

引用なし
パスワード
   こんにちは。
こんな感じでいかがでしょう。
AB列を作業列にしています。

Sub test()
  Dim myR As Range
  Dim myVal As Variant
  Dim myRow As Long
  Dim r As Range
  
  With Worksheets("sheet2")
     myVal = .Range("A2", .Range("A65536").End(xlUp)).Value
  End With
  
  With Worksheets("sheet1")
     Set myR = .Range("B5", .Range("B65536").End(xlUp))
       myRow = .Range("B65536").End(xlUp).Row
    For i = 1 To UBound(myVal, 1)
     For Each r In myR
     If InStr(r.Value, myVal(i, 1)) > 0 Then
       r.Offset(0, 26).Value = 1
     End If
     Next
    Next
   
    With Range("AB5:AB" & myRow)
     Application.DisplayAlerts = False
     .SpecialCells(xlCellTypeBlanks).EntireRow.Delete
     Application.DisplayAlerts = True
     .Value = ClearContents
    End With
  End With

End Sub

【25136】Re:検索→削除
質問  いづみ  - 05/5/21(土) 0:03 -

引用なし
パスワード
   ▼ponpon さん:

ありがとうございます。早速試してみました。
下記のように少し加えてたのですが、最後にsheet1のA5からの表の
削除がうまくいきません。
特にエラーもでないのですが、なぜでしょうか。
よろしくお願いいたします。

Sub 検索から削除()
  Dim dayR As Range
  Dim moVa As Variant
  Dim dayLo As Long
  Dim r As Range
  Dim shtName As String
  Dim i As Long

 
  With Worksheets("ワード")
     moVa = .Range("A2", .Range("A65536").End(xlUp)).Value
  End With
 
  With Worksheets("sheet1")
     Set dayR = .Range("B5", .Range("B65536").End(xlUp))
       dayLo = .Range("B65536").End(xlUp).Row
    For i = 1 To UBound(moVa, 1)
     For Each r In dayR
     If InStr(r.Value, moVa(i, 1)) > 0 Then
       r.Offset(0, 26).Value = 1
     End If
     Next
    Next
  
    With Range("AB5:AB" & dayLo)
     Application.DisplayAlerts = False
     .SpecialCells(xlCellTypeBlanks).EntireRow.Delete
     Application.DisplayAlerts = True
     .Value = ClearContents
   
    End With
  End With

MsgBox "現在のシートをコピーします"
 
ReName:
  shtName = Application.InputBox("シート名を入力して下さい。", "シート名入力", Type:=2)

  If shtName = "False" Then
    MsgBox "キャンセルしました。"
    Exit Sub
  End If

  For i = 1 To Worksheets.Count
    If Worksheets(i).Name = shtName Then
      MsgBox shtName & " は、既にあります。", vbExclamation, "エラー"
      GoTo ReName
    End If
  Next i


  On Error GoTo WrongName
    ActiveSheet.Copy after:=Worksheets(3)
    ActiveSheet.Name = shtName
  On Error GoTo 0
 
  MsgBox "完了"
  Exit Sub

WrongName:
  MsgBox "シート名に使えない文字が含まれています。", vbExclamation, "エラー"
  shtName = Application.InputBox("シート名を入力して下さい。", "シート名入力", Type:=2)
  
   Worksheets("sheet1").Range("A5:E999").Delete

End Sub

【25137】Re:検索→削除
回答  ponpon  - 05/5/21(土) 13:07 -

引用なし
パスワード
   こんにちは。
私も初心者で詳しくはないのですが、

>MsgBox "完了"
>Exit Sub

では、
後のコードは走らないのでは?
それと
>Worksheets("sheet1").Range("A5:E999").Delete
でDeleteよりはClearContentsがよいと思います。
削除は重いです。

私が気がつくのは、これくらいです。

後は、私が例示したコードも含め、常連の方の
回答をお待ちください。

【25138】Re:検索→削除
発言  kobasan  - 05/5/21(土) 15:17 -

引用なし
パスワード
   ▼ponpon さん、いづみさん今日は。

抽出でやってみました。
試してみてください。
'
'プログラムの流れは、以下の通りです。
'Sheet3に抽出結果を出力し、その結果をSheet1に貼り付けしました。
'

Sub 絞込みコピー貼付()
Dim c As Range
Dim AutoFkey() As Variant
  Application.ScreenUpdating = False
  Sheets(3).Cells().ClearContents
  '-----タイトル行をコピー・貼付
  With Sheets(1)
    .Range("A5", .Cells(5, 256).End(xlToLeft)).Copy
  End With
  Sheets(3).Cells(1, 1).PasteSpecial Paste:=xlValues
  '-----抽出key格納
  With Worksheets("sheet2")
     AutoFkey = .Range("A2", .Range("A65536").End(xlUp)).Value
  End With
  '-----抽出・コピー・貼付
  For i = 1 To UBound(AutoFkey, 1)
    '-----抽出・コピー
    Sheets(1).Range("A4").AutoFilter Field:=2, Criteria1:="*" & AutoFkey(i, 1) & "*"
    Sheets(1).AutoFilter.Range.CurrentRegion.Offset(1).Copy
    '-----貼付
    Sheets(3).Cells(65536, 1).End(xlUp).Offset(1, 0).PasteSpecial Paste:=xlValues
    Sheets(1).AutoFilterMode = False  'AutoFilterの解除
  Next
  Paste結果
  Application.CutCopyMode = False   'CopyModeの解除
  Sheets(1).Select
End Sub

Sub Paste結果()
  Lrow = Sheets(1).Cells(65536, 1).End(xlUp).Row
  Sheets(1).Rows("5:" & Lrow).ClearContents  'shee1のデータ消去
  '
  Lrow = Sheets(3).Cells(65536, 1).End(xlUp).Row
  Sheets(3).Rows("2:" & Lrow).Copy
  Sheets(1).Cells(5, 1).PasteSpecial Paste:=xlValues '結果をsheet1に貼付
End Sub

【25141】Re:検索→削除
発言  ponpon  - 05/5/21(土) 21:42 -

引用なし
パスワード
   こんばんは。
逆の発想ですね。
なるほど。
クラスモジュールの時はありがとうございました。
未だに自由に使い切れてないですが。
脱初心者を目指していろいろと回答しているのですが、
ドジばっかりで。
でも、少しずつ進歩しているのが、自分でもわかります。
また、今度質問の時はよろしくお願いします。

▼いづみさん おじゃまして申し訳ありません。

【25145】Re:検索→削除
回答  ちゃっぴ  - 05/5/22(日) 13:13 -

引用なし
パスワード
   配列でゴリゴリ・・・

Const WORD_START_ROW As Long = 2&
Const TARGET_START_ROW As Long = 5&

Sub S_Main()
  Dim rngDataArea As Excel.Range
  Dim vntIndex  As Variant
  Dim vntData   As Variant
  Dim vntUpdate  As Variant

  ' Dataを配列に格納
  With Worksheets("ワード").Cells(WORD_START_ROW, 1)
    With .Resize(.Offset(65536 - WORD_START_ROW).End(xlUp).Row - WORD_START_ROW + 1)
      .AdvancedFilter Action:=xlFilterInPlace, Unique:=True
    End With
    vntIndex = .Resize(.End(xlDown).Row - WORD_START_ROW + 1).Value
  End With
  
  With Worksheets("sheet1").Cells(TARGET_START_ROW, 1)
    Set rngDataArea = .Resize( _
      .Offset(65536 - TARGET_START_ROW).End(xlUp).Row _
      - TARGET_START_ROW + 1, 5)
  End With
  vntData = rngDataArea.Value
  
  ' Matching
  vntUpdate = F_strEraseMatchData(vntData, vntIndex)
  
  rngDataArea.Value = vntUpdate
  
  'Call S_CopySheet(Worksheets("sheet1"))
End Sub


Function F_strEraseMatchData( _
  vntOriginal As Variant, _
  vntIndex As Variant) As String()
  
  Dim strUpdate() As String
  Dim vntBuf   As Variant
  Dim lngRows   As Long
  Dim lngColumns As Long
  Dim i      As Long
  Dim j      As Long
  Dim k      As Long
  
  lngRows = UBound(vntOriginal, 1)
  lngColumns = UBound(vntOriginal, 2)
  
  ReDim strUpdate(1 To lngRows, 1 To lngColumns)
  
  For i = 1 To lngRows
    For Each vntBuf In vntIndex
      If InStr(1, vntOriginal(i, 2), _
        vntBuf, vbTextCompare) > 0 Then
        
        j = j + 1
        For k = 1 To lngColumns
          strUpdate(j, k) = vntOriginal(i, k)
        Next k
        Exit For
      End If
    Next
  Next i
  
  F_strEraseMatchData = strUpdate
End Function

Sub S_CopySheet(wstTarget As Worksheet)
  Dim strShtName As String
  
  wstTarget.Copy After:=Worksheets(3)
  
  Do
    strShtName = Application.InputBox( _
      "シート名を入力して下さい。", "シート名入力", Type:=2)
    
    If strShtName = "False" Then
      MsgBox "キャンセルしました。"
      Worksheets(4).Delete
      Exit Sub
    End If
    
    On Error Resume Next
    Worksheets(4).Name = strShtName
    If Err.Number <> 0 Then
      MsgBox "同名のSheetが存在するか、使用不可能な文字が含まれています。" & vbLf _
        & "'" & shtName & "'"
    Else
      On Error GoTo 0
      Exit Do
    End If
  Loop
  
  MsgBox "完了"
End Sub

【25146】Re:検索→削除
質問  いづみ  - 05/5/22(日) 15:00 -

引用なし
パスワード
   みなさん有難うございます。

ちゃっぴさんのを試してみたらデータは
うまく取り出せるのですが、メッセージBOXが
でてきませんでした。
かなり難しすぎてぜんぜん分かりません(>_<)
Function というのも初めてです。

ちゃっぴさんが書いてくれたのをそのまま
モジュールに貼り付けたのでは
だめなのでしょうか?

よろしければ教えてください。
お願いします。

【25151】Re:検索→削除
回答  ちゃっぴ  - 05/5/22(日) 22:13 -

引用なし
パスワード
   >ちゃっぴさんのを試してみたらデータは
>うまく取り出せるのですが、メッセージBOXが
>でてきませんでした。

その部分を Comment Out していたからです。
# もっともMissがあったので動きませんが・・・

>かなり難しすぎてぜんぜん分かりません(>_<)
>Function というのも初めてです。

Functionは基本なのでこの際きちんと理解しましょう。
簡単に言うと、Sub は値を返しませんが、
Functionは値を返します。

最近、まともなのかいてなかったので・・・
Class をつかわないでやるんでしたら、こんな感じで私はやりますね。

Private Const WORDS_SHEET_NAME As String = "ワード"
Private Const WORDS_START_ROW As Long = 2&
Private Const WORDS_START_COL As Long = 1&
Private Const WORDS_END_COL As Long = 1&

Private Const DATA_SHEET_NAME As String = "sheet1"
Private Const DATA_START_ROW As Long = 5&
Private Const DATA_START_COL As Long = 1&
Private Const DATA_END_COL As Long = 5&

Public Sub S_Main()
  Dim wstDataSheet  As Excel.Worksheet
  Dim wstCopiedSheet As Excel.Worksheet
  Dim rngDataArea   As Excel.Range
  Dim vntWordsList  As Variant
  Dim vntData     As Variant
  Dim vntUpdate    As Variant

  ' Dataを配列に格納
  Set wstDataSheet = Worksheets(DATA_SHEET_NAME)
  Set rngDataArea = F_rngGetDataArea(wstDataSheet, _
    DATA_START_ROW, DATA_START_COL, DATA_END_COL)
  If rngDataArea Is Nothing Then
    MsgBox "Dataが存在しません。", vbCritical
    GoTo L_Ending
  End If
  vntData = rngDataArea.Value
  
  ' SheetのCopy
  Set wstCopiedSheet = F_wstCopySheet(wstDataSheet, Worksheets(3))
  If wstCopiedSheet Is Nothing Then GoTo L_Ending

  ' Words List を作成
  vntWordsList = F_vntMakeWordsList( _
    F_rngGetDataArea(Worksheets(WORDS_SHEET_NAME), _
    WORDS_START_ROW, WORDS_START_COL, WORDS_END_COL))
  
  ' Matching
  vntUpdate = F_strEraseMatchData(vntData, vntWordsList)
  
  ' Copy Sheet に Data出力
  wstCopiedSheet.Cells(DATA_START_ROW, DATA_START_COL) _
    .Resize(UBound(vntUpdate, 1), UBound(vntUpdate, 2)).Value _
      = vntUpdate
  
  ' Sheet Data の消去
  rngDataArea.ClearContents
  
  MsgBox "処理が完了しました", vbInformation
  
L_Ending:
  Set wstDataSheet = Nothing
  Set wstCopiedSheet = Nothing
  Set rngDataArea = Nothing
End Sub

' WordsList(配列:1次元)を作成
Private Function F_vntMakeWordsList(rngTarget As Excel.Range) As Variant
  Dim dicList   As Scripting.Dictionary
  Dim vntList   As Variant
  Dim vntbuf   As Variant
  
  If rngTarget Is Nothing Then
    vntList = Array("")
  Else
    ' 重複を削除
    Set dicList = New Scripting.Dictionary
    For Each vntbuf In rngTarget.Value
      dicList.Item(vntbuf) = ""
    Next
    vntList = dicList.Keys
    Set dicList = Nothing
  End If
  
  ' Return
  F_vntMakeWordsList = vntList
End Function

' Data範囲を取得
Private Function F_rngGetDataArea( _
  ByVal wstTarget As Excel.Worksheet, _
  ByVal lngStartRow As Long, _
  ByVal lngStartCol As Long, _
  ByVal lngEndCol As Long) As Excel.Range
  
  Dim rngStart    As Excel.Range
  Dim rngEnd     As Excel.Range
  Dim lngColOffset  As Long
  
  lngColOffset = lngEndCol - lngStartCol
  With wstTarget
    Set rngStart = .Cells(lngStartRow, lngStartCol)
    Set rngEnd = .Cells(.Rows.Count, lngStartCol)
  End With
  
  If rngStart.Value = "" Then GoTo L_Ending
  
  If rngEnd.Value = "" Then
    Set rngEnd = rngEnd.End(xlUp).Offset(, lngColOffset)
  Else
    Set rngEnd = rngEnd.Offset(, lngColOffset)
  End If
  
  Set F_rngGetDataArea _
    = wstTarget.Range(rngStart, rngEnd)
  
L_Ending:
  Set rngStart = Nothing
  Set rngEnd = Nothing
End Function

' Matchingし、有効なDataのみを返す
Private Function F_strEraseMatchData( _
  vntOriginal As Variant, _
  vntIndex As Variant) As String()
  
  Dim strUpdate() As String
  Dim vntbuf   As Variant
  Dim lngRows   As Long
  Dim lngColumns As Long
  Dim i      As Long
  Dim j      As Long
  Dim k      As Long
  
  lngRows = UBound(vntOriginal, 1)
  lngColumns = UBound(vntOriginal, 2)
  
  ReDim strUpdate(1 To lngRows, 1 To lngColumns)
  
  For i = 1 To lngRows
    For Each vntbuf In vntIndex
      If InStr(1, vntOriginal(i, 2), _
        vntbuf, vbTextCompare) > 0 Then
        
        j = j + 1
        For k = 1 To lngColumns
          strUpdate(j, k) = vntOriginal(i, k)
        Next k
        Exit For
      End If
    Next
  Next i
  
  F_strEraseMatchData = strUpdate
End Function

' SheetのCopy & Rename
Private Function F_wstCopySheet( _
  ByVal wstTarget As Excel.Worksheet, _
  ByVal wstAfterDestination As Excel.Worksheet _
  ) As Excel.Worksheet
  
  Dim wstCopiedSheet As Excel.Worksheet
  Dim strShtName   As String
  
  wstTarget.Copy After:=wstAfterDestination
  Set wstCopiedSheet = Worksheets(wstAfterDestination.Index + 1)
  
  Do
    strShtName = Application.InputBox( _
      "シート名を入力して下さい。", "シート名入力", Type:=2)
    
    If strShtName = "False" Then
      Application.DisplayAlerts = False
      wstCopiedSheet.Delete
      Application.DisplayAlerts = True
      Set wstCopiedSheet = Nothing
      Exit Function
    End If
    
    On Error Resume Next
    wstCopiedSheet.Name = strShtName
    If Err.Number <> 0 Then
      MsgBox "同名のSheetが存在するか、使用不可能な文字が含まれています。" & vbLf _
        & "'" & strShtName & "'", vbExclamation
    Else
      On Error GoTo 0
      Exit Do
    End If
  Loop

  Set F_wstCopySheet = wstCopiedSheet
  Set wstCopiedSheet = Nothing
End Function

そんなに難しいことはやっていないので、
がんばって理解してください。

9848 / 13646 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free