Ngô Hải Đăng
Thành viên hoạt động



			
		- Tham gia
 - 31/8/17
 
- Bài viết
 - 183
 
- Được thích
 - 247
 
- Giới tính
 - Nam
 
Hàm nhận 2 tham số iArray (Mảng hoặc Range) và iFilter as String (điều kiện Filter)
Các điều kiện được nối với nhau bởi OR, AND, ]OR[, ]AND[ theo mức độ ưu tiên từ cao đến thấp như sau: ]AND[ >> ]OR[ >> AND >> OR.
Các toán tử so sánh gồm: LIKE, !LIKE, <, <=, >, >=, =, <>. Trong đó LIKE và !LIKE dùng cho Text và Text phải được đặt trong 2 dấu nháy đơn (Ví dụ: 'Giải pháp Excel')
Chuỗi Filter được viết theo cú pháp như sau: [5] > 100 AND [3] LIKE '*GPE*'
Trong đó[5] và [3] là cột cần Filter, các toán tử so sánh và các phép nối OR AND đều phải cách ra 1 khoảng trắng.
Trường hợp cần so sánh ngày thì ta phải thêm # trước ngày cần so sánh (Ví dụ: [1] > #21/12/2020)
Trường hợp có sử dụng công thức thì phải thêm ? đứng trước (Ví dụ: ?[3]*[4] > 1000000 hoặc là ?Year([1]) = 2020 hoặc là ?Left([2],3) = 'GPE')
Code trong Module
	
	
	
		
Code Test
	
	
	
		
				
			Các điều kiện được nối với nhau bởi OR, AND, ]OR[, ]AND[ theo mức độ ưu tiên từ cao đến thấp như sau: ]AND[ >> ]OR[ >> AND >> OR.
Các toán tử so sánh gồm: LIKE, !LIKE, <, <=, >, >=, =, <>. Trong đó LIKE và !LIKE dùng cho Text và Text phải được đặt trong 2 dấu nháy đơn (Ví dụ: 'Giải pháp Excel')
Chuỗi Filter được viết theo cú pháp như sau: [5] > 100 AND [3] LIKE '*GPE*'
Trong đó[5] và [3] là cột cần Filter, các toán tử so sánh và các phép nối OR AND đều phải cách ra 1 khoảng trắng.
Trường hợp cần so sánh ngày thì ta phải thêm # trước ngày cần so sánh (Ví dụ: [1] > #21/12/2020)
Trường hợp có sử dụng công thức thì phải thêm ? đứng trước (Ví dụ: ?[3]*[4] > 1000000 hoặc là ?Year([1]) = 2020 hoặc là ?Left([2],3) = 'GPE')
Code trong Module
		PHP:
		
	
	Function FilterArray2D(ByVal iArray, ByVal iFilter As String)
  Dim x&, y&, z&, minY&, maxY&, minX&, maxX&, sF$
  Dim yI(), xF(), aX
  ReDim aX(1 To 1, 1 To 1)
  If iFilter = "" Then
    aX(1, 1) = "Không có Filter..."
  Else
    If TypeName(iArray) = "Range" Then iArray = iArray.Value
    MakeFilter iFilter
    minX = LBound(iArray, 2): maxX = UBound(iArray, 2)
    For x = 1 To maxX - minX + 1
      If InStr(1, iFilter, "[" & vbBack & vbBack & x & vbBack & vbBack & "]", vbTextCompare) > 0 Then
        z = z + 1: ReDim Preserve xF(1 To z): xF(z) = x
      End If
    Next x
    If z = 0 Then
      aX(1, 1) = "Filter sai..."
    Else
      z = 0
      minY = LBound(iArray, 1): maxY = UBound(iArray, 1)
      For y = minY To maxY
        sF = iFilter
        For x = 1 To UBound(xF)
          sF = Replace(sF, "[" & vbBack & vbBack & xF(x) & vbBack & vbBack & "]", GetValueArray(iArray(y, xF(x) - 1 + minX)), , , vbTextCompare)
        Next x
        If CheckFilter(sF) Then z = z + 1: ReDim Preserve yI(1 To z): yI(z) = y
      Next y
      If z = 0 Then
        aX(1, 1) = "Không tìm ra..."
      Else
        ReDim aX(1 To z, 1 To maxX - minX + 1)
        For y = 1 To z
          For x = 1 To maxX - minX + 1
            aX(y, x) = iArray(yI(y), x - 1 + minX)
          Next x
        Next y
      End If
    End If
  End If
  FilterArray2D = aX
End Function
Private Sub MakeFilter(iFilter As String)
  Dim xBeginText&, xEndText&, sText$, x&, aCompare
  iFilter = WorksheetFunction.Trim(iFilter)
  iFilter = Replace(iFilter, "[", "[" & vbBack & vbBack)
  iFilter = Replace(iFilter, "]", vbBack & vbBack & "]")
  iFilter = Replace(iFilter, " ", vbBack, , , vbTextCompare)
  iFilter = Replace(iFilter, vbBack & vbBack & vbBack, vbBack)
  xBeginText = InStr(1, iFilter, "'") + 1
  While xBeginText > 1
    xEndText = InStr(xBeginText, iFilter, "'") + 1
    sText = Mid(iFilter, xBeginText, xEndText - xBeginText)
    iFilter = Replace(iFilter, sText, Replace(sText, vbBack & vbBack, ""))
    iFilter = Replace(iFilter, sText, Replace(sText, vbBack, " "))
    xBeginText = InStr(xEndText, iFilter, "'") + 1
  Wend
  aCompare = Array("!like", "<=", ">=", "<>", "like", "<", ">", "=")
  For x = 0 To UBound(aCompare)
    iFilter = Replace(iFilter, vbBack & aCompare(x) & vbBack, vbBack & x & vbBack, , , vbTextCompare)
  Next x
End Sub
Private Function GetValueArray(iValue)
  Select Case TypeName(iValue)
    Case Is = "String", "Null", "Empty", "Error": GetValueArray = "'" & CStr(iValue) & "'"
    Case Else: GetValueArray = CDbl(iValue)
  End Select
End Function
Private Function CheckFilter(ByVal iFilter As String) As Boolean
  Dim aF: aF = Split(iFilter, vbBack & "]AND[" & vbBack, , vbTextCompare)
  Dim x&
  For x = LBound(aF) To UBound(aF)
    If Not CheckFilter1(aF(x)) Then Exit Function
  Next x
  CheckFilter = True
End Function
Private Function CheckFilter1(ByVal iFilter As String) As Boolean
  Dim aF: aF = Split(iFilter, vbBack & "]OR[" & vbBack, , vbTextCompare)
  Dim x&
  For x = LBound(aF) To UBound(aF)
    If CheckFilter2(aF(x)) Then CheckFilter1 = True: Exit Function
  Next x
End Function
Private Function CheckFilter2(ByVal iFilter As String) As Boolean
  Dim aF: aF = Split(iFilter, vbBack & "AND" & vbBack, , vbTextCompare)
  Dim x&
  For x = LBound(aF) To UBound(aF)
    If Not CheckFilter3(aF(x)) Then Exit Function
  Next x
  CheckFilter2 = True
End Function
Private Function CheckFilter3(ByVal iFilter As String) As Boolean
  Dim aF: aF = Split(iFilter, vbBack & "OR" & vbBack, , vbTextCompare)
  Dim x&
  For x = LBound(aF) To UBound(aF)
    If CheckFilter4(aF(x)) Then CheckFilter3 = True: Exit Function
  Next x
End Function
Private Function CheckFilter4(ByVal iFilter As String) As Boolean
  Dim aF: aF = Split(iFilter, vbBack)
  Dim u1, u2
  u1 = GetValueFilter(aF(0)): If IsArray(u1) Then Exit Function
  u2 = GetValueFilter(aF(2)): If IsArray(u2) Then Exit Function
  Select Case aF(1)
    Case Is = 0: CheckFilter4 = Not u1 Like u2
    Case Is = 1: CheckFilter4 = u1 <= u2
    Case Is = 2: CheckFilter4 = u1 >= u2
    Case Is = 3: CheckFilter4 = u1 <> u2
    Case Is = 4: CheckFilter4 = u1 Like u2
    Case Is = 5: CheckFilter4 = u1 < u2
    Case Is = 6: CheckFilter4 = u1 > u2
    Case Is = 7: CheckFilter4 = u1 = u2
  End Select
End Function
Private Function GetValueFilter(ByVal iString As String)
  On Error GoTo HError
  Select Case Left$(iString, 1)
    Case Is = "'": GetValueFilter = Mid(iString, 2, Len(iString) - 2)
    Case Is = "?": GetValueFilter = Evaluate("=" & Mid(iString, 2))
    Case Is = "#": GetValueFilter = CDbl(CDate(Mid(Replace(iString, "'", ""), 2)))
    Case Else: GetValueFilter = Val(iString)
  End Select
  Exit Function
HError:
GetValueFilter = Array(1)
End Function
	Code Test
		PHP:
		
	
	Sub TestFilterArray2D()
  Dim sFilter$, rData As Range, rResult As Range, aX, xTimer!
  xTimer = Timer
  'Dieu kien Filter
  sFilter = "[2] like 'KH*' and [5] like 'Kg' and [8] > 0"
  'Chon vung Du lieu can Filter
  Set rData = Sheet3.[A3:N9601]
  'Chon Cell de gan ket qua
  Set rResult = Sheet3.[P3]
  aX = FilterArray2D(rData.Value, sFilter)
  Application.ScreenUpdating = False
  rResult.Resize(rData.Rows.Count, rData.Columns.Count).ClearContents
  rResult.Resize(UBound(aX, 1), UBound(aX, 2)) = aX
  Application.ScreenUpdating = True
  MsgBox "Time is: " & Timer - xTimer
End Sub
	File đính kèm
			
				Lần chỉnh sửa cuối: 
			
		
	
								
								
									
	
								
							
							
	
	  



