2013-06-03 46 views
8

我正在創建一個快速子文件來對電子郵件進行有效性檢查。我想刪除'E'列中不包含'@'的整行聯繫人數據。我使用了下面的宏,但是它的運行速度太慢,因爲Excel在刪除後移動了所有的行。如果單元格不包含'@',則刪除整行的有效方法

我試過另一種技術:set rng = union(rng,c.EntireRow),然後刪除整個範圍,但我無法防止錯誤消息。

我也嘗試過只添加每行到一個選擇,並在所有內容被選中後(如在Ctrl + Select中),隨後刪除它,但我找不到適當的語法。

任何想法?

Sub Deleteit() 
    Application.ScreenUpdating = False 

    Dim pos As Integer 
    Dim c As Range 

    For Each c In Range("E:E") 

     pos = InStr(c.Value, "@") 
     If pos = 0 Then 
      c.EntireRow.Delete 
     End If 
    Next 

    Application.ScreenUpdating = True 
End Sub 
+0

首先,限制了細胞的數量來遍歷。即,而不是'範圍(E:E)',使用其中包含數據的範圍 – shahkalpesh

+0

我一直想知道如何做到這一點 - 如何選擇包含第一個單元格的範圍,直到包含數據的最後一個單元格? – Parseltongue

+1

http://www.rondebruin.nl/win/s4/win001.htm - 看看這個。我相信,它會爲你回答。回想你的問題,假設你在包含數據的單元格A1中,現在按Ctrl +向下箭頭。這將選擇所有從A1開始的單元格,直到包含數據的最後一個單元格爲止(注意:中間不應該有空單元格)。使用VBA,你可以'lastCell = Range(「A1」)。End(xlDown)' – shahkalpesh

回答

16

你不需要循環來做到這一點。自動過濾器效率更高。 (類似於光標對其中的SQL子句)

自動過濾不包含 「@」,然後所有的行刪除它們像這樣:

Sub KeepOnlyAtSymbolRows() 
    Dim ws As Worksheet 
    Dim rng As Range 
    Dim lastRow As Long 

    Set ws = ActiveWorkbook.Sheets("Sheet1") 

    lastRow = ws.Range("E" & ws.Rows.Count).End(xlUp).Row 

    Set rng = ws.Range("E1:E" & lastRow) 

    ' filter and delete all but header row 
    With rng 
     .AutoFilter Field:=1, Criteria1:="<>*@*" 
     .Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete 
    End With 

    ' turn off the filters 
    ws.AutoFilterMode = False 
End Sub 

注:

  • .Offset(1,0)阻止我們刪除標題行
  • .SpecialCells(xlCellTypeVisible)指定自動篩選器應用後剩餘的行
  • .EntireRow.Delete刪除所有可見的行標題以外的行

步執行代碼,你可以看到每行做什麼。在VBA編輯器中使用F8。

+0

我得到'下標超出範圍'的錯誤。你能解釋兩件事嗎? 'Set rng = ws.Range(「A1:A」&lastRow)是什麼?爲什麼「A1:A」?以及「.Offset(1,0).SpecialCells(xlCellTypeVisible).EntireRow.Delete」是做什麼的? – Parseltongue

+0

我剛剛意識到您正在使用的列是E.錯誤是因爲我在搜索錯誤的列。將「A」改爲「E」,它應該起作用。設置範圍指定我們要自動過濾的範圍(A1:A以及最後一行的值)。 .Offset(1,0)使我們不會刪除標題行。 –

+2

立即嘗試 - 我編輯了專欄。 –

2

使用用戶shahkalpesh提供的示例,我成功創建了以下宏。我仍然對學習其他技術感到好奇(比如Fnostro引用的一個技術,您可以在其中清除內容,排序,然後刪除)。我是VBA新手,所以任何示例都會非常有幫助。

Sub Delete_It() 
    Dim Firstrow As Long 
    Dim Lastrow As Long 
    Dim Lrow As Long 
    Dim CalcMode As Long 
    Dim ViewMode As Long 

    With Application 
     CalcMode = .Calculation 
     .Calculation = xlCalculationManual 
     .ScreenUpdating = False 
    End With 

    With ActiveSheet 
     .Select 
     ViewMode = ActiveWindow.View 
     ActiveWindow.View = xlNormalView 
     .DisplayPageBreaks = False 

     'Firstrow = .UsedRange.Cells(1).Row 
     Firstrow = 2 
     Lastrow = .Cells(.Rows.Count, "E").End(xlUp).Row 

     For Lrow = Lastrow To Firstrow Step -1 
      With .Cells(Lrow, "E") 
       If Not IsError(.Value) Then 
        If InStr(.Value, "@") = 0 Then .EntireRow.Delete 
       End If 
      End With 
     Next Lrow 
     End With 

    ActiveWindow.View = ViewMode 
    With Application 
     .ScreenUpdating = True 
     .Calculation = CalcMode 
    End With 

End Sub 
+0

完成代碼工作,但儘可能避免範圍循環 - 它們在較大的數據集上可能非常緩慢。如有可能,請使用「AutoFilter」,「SpecialCells」或變體陣列。 – brettdj

3

您是否嘗試過使用「@」爲準則,然後使用

specialcells(xlcelltypevisible).entirerow.delete 

注意到一個簡單的自動過濾:之前和之後@有星號,但我不知道該怎麼阻止他們被解析出來!

+0

道歉 - 當我最初發布時,你的回答不在那裏。儘管我確實搞亂了標準! – JosieP

1

當你與許多行和許多條件下工作,你最好不要使用行刪除的這種方法

Option Explicit 

Sub DeleteEmptyRows() 
    Application.ScreenUpdating = False 

    Dim ws As Worksheet 
    Dim i&, lr&, rowsToDelete$, lookFor$ 

    '*!!!* set the condition for row deletion 
    lookFor = "@" 

    Set ws = ThisWorkbook.Sheets("Sheet1") 
    lr = ws.Range("E" & Rows.Count).End(xlUp).Row 

    ReDim arr(0) 

    For i = 1 To lr 
    If StrComp(CStr(ws.Range("E" & i).Text), lookFor, vbTextCompare) = 0 then 
     ' nothing 
    Else 
     ReDim Preserve arr(UBound(arr) + 1) 
     arr(UBound(arr) - 1) = i 
    End If 
    Next i 

    If UBound(arr) > 0 Then 
     ReDim Preserve arr(UBound(arr) - 1) 
     For i = LBound(arr) To UBound(arr) 
      rowsToDelete = rowsToDelete & arr(i) & ":" & arr(i) & "," 
     Next i 

     ws.Range(Left(rowsToDelete, Len(rowsToDelete) - 1)).Delete Shift:=xlUp 
    Else 
     Application.ScreenUpdating = True 
     MsgBox "No more rows contain: " & lookFor & "or" & lookFor2 & ", therefore exiting" 
     Exit Sub 
    End If 

    If Not Application.ScreenUpdating Then Application.ScreenUpdating = True 
    Set ws = Nothing 
End Sub 
+0

'Select'減慢任何代碼,應始終避免。我懷疑這可能會影響過濾效率。 – brettdj

0

相反的循環和1個參考各小區1,抓住一切,把它變成一個變種陣列;然後循環變體數組。

入門:

Sub Sample() 
    ' Look in Column D, starting at row 2 
    DeleteRowsWithValue "@", 4, 2 
End Sub 

真正的工人:

Sub DeleteRowsWithValue(Value As String, Column As Long, StartingRow As Long, Optional Sheet) 
Dim i As Long, LastRow As Long 
Dim vData() As Variant 
Dim DeleteAddress As String 

    ' Sheet is a Variant, so we test if it was passed or not. 
    If IsMissing(Sheet) Then Set Sheet = ActiveSheet 
    ' Get the last row 
    LastRow = Sheet.Cells(Sheet.Rows.Count, Column).End(xlUp).Row 
    ' Make sure that there is work to be done 
    If LastRow < StartingRow Then Exit Sub 

    ' The Key to speeding up the function is only reading the cells once 
    ' and dumping the values to a variant array, vData 
    vData = Sheet.Cells(StartingRow, Column) _ 
       .Resize(LastRow - StartingRow + 1, 1).Value 
    ' vData will look like vData(1 to nRows, 1 to 1) 
    For i = LBound(vData) To UBound(vData) 
     ' Find the value inside of the cell 
     If InStr(vData(i, 1), Value) > 0 Then 
      ' Adding the StartingRow so that everything lines up properly 
      DeleteAddress = DeleteAddress & ",A" & (StartingRow + i - 1) 
     End If 
    Next 
    If DeleteAddress <> vbNullString Then 
     ' remove the first "," 
     DeleteAddress = Mid(DeleteAddress, 2) 
     ' Delete all the Rows 
     Sheet.Range(DeleteAddress).EntireRow.Delete 
    End If 
End Sub 
相關問題