Bài viết: Viết hàm VBA như thế nào là tốt

Liên hệ QC

Pansy_flower

...nợ người, nợ đời...
Thành viên danh dự
Tham gia
3/6/06
Bài viết
1,611
Được thích
14,001
Nghề nghiệp
...thiết kế máy bay cho VOI tự lái...^.^
Chúng ta biết tại sao chỉ có mấy hàm của Excel mà chúng ta mỗi người mỗi nghề có thể dùng nó để giải quyết công việc. Các hàm được xây dựng phải giải quyết theo hướng tổng quát không nên cụ thể một chi tiết trừ khi bắt buộc. Người dùng Excel có thể vận dụng hàm để sáng tác ra các công thức khác nhau, sự thông minh (công thức ngắn gọn+tốc độ xửa lý nhanh+dễ nhớ...) của nó tùy vào sáng tạo và tư duy của mỗi người. Đây chính là điểm mạnh của Excel và làm cho chúng ta cứ như mắc nợ Excel!

Chắc hẳn chúng ta ai cũng muốn mình học VBA để biết tạo ra các hàm không những cho mình và cả những người khác sử dụng! Vậy chúng nên thiết kế hàm như thế nào là tốt nhất? Để giải quyết câu hỏi này chúng ta bắt đầu từng việc:


1-Khai báo và đặt tên Thủ tục, Hàm, Biến, Hằng (Sub, Function, Dim, Const)


Bàn vào việc đặt tên mỗi người nên chọn một kiểu gọi là "chuẩn", có thể bằng tiếng Anh hay Việt. Theo tôi các bạn nên đặt theo tiếng Anh vì ngắn gọn hơn.

Việc đặt tên thực sự rất quan trọng (chúng ta trân trọng như là đặt tên cho con mình). Các bạn hình dung thế này, nếu chúng ta có hàng trăm phương tiện, công cụ làm việc, khi cần một việc gì đó chúng ta cần gọi nó ra ngay thì liệu chúng ta có nhớ tên gọi của nó không? Phương pháp đặt tên để giúp ta dễ nhớ hơn.

+ Tên Thủ tục, Hàm:
Tên phải hàm ý về nội dung giải quyết của nó. Điều quan trọng là không được trùng với từ khóa của Excel. Ví dụ không được đặt tên là "Sub", "Do", "Loop" hay các hàm sẵn có của VBA là "Left", "Right",...

Ví dụ tôi muốn tạo một hàm để tìm chuỗi, vậy tên tôi sẽ đặt tên function là "Timchuoi", "BatdaulaChuhoa" là hàm đổi các ký tự đầu của mỗi từ thành chữ hoa (Trong Excel có hàm Proper để làm nhưng hàm này bị lỗi với font với kiểu gõ không phải Unicode và có dấu), tại sao không đặt là "Chuhoa" để ngắn hơn? Vì có thể bị nhầm sang đổi chuỗi thành chữ hoa (UPPER, VBA-Ucase).
Chúng ta đặt tên sao cho không bị nhầm chức năng.
Trong VBA khai báo như sau

PHP:
Function Timchuoi()
End Function
 
Function BatdaulaChuhoa()
End Function


+ Tên Dim, Const:
Cách thức cũng như phần đặ tên cho Sub/Function nhưng thêm các ký tự định nghĩa để làm sáng tỏ kiểu giá trị (Type)
Kiểu giá trị gồm: String, Byte, Integer, Long, Date, Object, Boolean....
Với tôi, tôi hay đặt tên với phần đầu là kiểu giá trị, các kiểu Byte, Integer, Long thì dùng chữ "n"-Number để đại diện vì cơ bản là giá trị số. Kiểu Boolean thì dùng chuỗi "Is".

Mã:
Dim strHoTen as String
Dim IsNam as Boolean
Dim dNgay as Date
......

Khi tôi viết hướng dẫn sử dụng hàm LEFT trên Excel tôi viết cấu trúc thế này LEFT(strChuoi, nKytu). Như vậy thì ta hiểu đối số đầu tiên là kiểu String - Chuỗi văn bản, nKytu là giá trị đưa vào kiểu số.

Có nhiều bạn khi khai báo kiểu giá trị thường hay bỏ lửng như Dim strHoTen mà không có kết thúc là "String" - Không nên chút nào! Việc xác định rõ giá trị còn là quy ước khi sử dụng chúng trong thân chương trình.

+ Xác định tham số cho Sub, Function

Nhắc lại về hàm LEFT(strChuoi, nKytu). Chúng ta cứ tự hỏi tại sao phải có 2 đối số? Tại sao? Muốn lấy bên trái với n ký tự thì buộc người dùng phải đưa vào strChuoi - chuối để lấy, nKytu là số ký tự cần lấy.

Như vậy tham số cho Sub, Function là những tham số mà người dùng phải buộc đưa vào thì Sub, Function mới xử lý được. Tên các tham số này người dùng (bất kỳ ai sử dụng) phải gần như tự đọc hiểu được).

Có một ví dụ về kiểu khai báo thế này:


Function Tachten(St as String,Bt as Integer)
St, Bt là cái gì? Viết thế này thì chỉ có tác giả mới hiểu và đến lúc nào đó chính họ sẽ không biết nó là cái gì nữa!

Khi đưa biến vào làm tham số chúng ta cũng cần chú ý một cách để Optional - Tùy ý và gán giá trị ngầm định.


Ví dụ:
PHP:
Function Timchuoi(Byval strChuoi as String,Byval strChuoiTim as String, _
      Optional Byval TuBenTrai as Boolean = True) as Long
End Function

Hàm "Timchuoi" để tìm strChuoiTim trong strChuoi, ngầm định (Optional) tìm từ trái sang phải.
A1="090 4210337"
=Timchuoi(A1," ")

Hàm sẽ tìm ký tự " " trong ô A1 và trả về vị trí tìm được, chúng ta nếu tìm từ trái thì không cần phải vào tham số thứ 3 vì ngầm định TuBenTrai=True rồi
Nếu tìm từ bên phải thì =Timchuoi(A1," ", False)

Chúng ta gán Optional đầu tiên trước khai báo Byval hay Byref khi biết chắc đa số mọi người sẽ quy ước biến này về một giá trị nào đó, sử dụng Optional để người dùng sử dụng ngắn gọn hơn (Bản chất là ta khai báo giá trị tham số giúp cho người dùng).

2- Tạo ra Sub, Function để giải quyết mấu chốt công việc, khai thác triệt để các hàm sãn có

Chúng viết các Sub, Function là để giải quyết mấu chốt công việc, không nên quá cụ thể nếu điều đó không phải là bắt buộc.

Tôi sẽ viết hàm "Timchuoi". Hàm này sẽ tìm chuỗi từ trái sang phải hoặc ngược lại, kết quả tìm được sẽ cho ra một số >0 là vị trí tìm được, =0 nếu không tìm được.

Cách 1

PHP:
Function Timchuoi(Byval strChuoi as String, Byval strChuoiTim as String, _
      Optional Byval TuBenTrai as Boolean = True) as Long
Dim I as Long
Dim nKytuChuoitim as Long
Dim nKytuChuoi as Long
nKytuChuoi=Len(strChuoi)
nKytuChuoitim =Len(strChuoiTim)
 
If nKytuChuoi<nKytuChuoitim then Exit Function
 
    If TuBenTrai Then
        For I=1 To nKytuChuoi
            If Mid(strChuoi,I,nKytuChuoitim)=strChuoiTim Then
                Timchuoi=I
                Goto Done:
            End if
        Next I
     Else
         For I=nKytuChuoi To 1 Step -1
             If Not (nKytuChuoi-I< nKytuChuoitim) Then
                 If Mid(strChuoi,I,nKytuChuoitim)=strChuoiTim Then
                    Timchuoi=I
                     Goto Done:
                  End if
             End if
        Next I
    End If 
  Done:
End Function
Mặc dù Cách 1 Khá chặt chẽ nhưng không hay chút nào vì vừa dài lại vừa không khai thác các hàm mà VBA đã cung cấp->Tốc độ xử lý rất có thể bị chậm hơn nhiều với việc áp dụng hàm đã có

Cách 2: 'Khai thác hàm đã có Instr và InstrRev


PHP:
Function Timchuoi(Byval strChuoi as String, Byval strChuoiTim as String, _
           Optional Byval TuBenTrai as Boolean = True) as Long
Dim I as Long
Dim nKytuChuoitim as Long
Dim nKytuChuoi as Long
nKytuChuoi=Len(strChuoi)
nKytuChuoitim =Len(strChuoiTim)
 
If nKytuChuoi<nKytuChuoitim then Exit Function
 
If TuBenTrai Then
    Timchuoi=Instr(strChuoi,strChuoiTim)
Else
    Timchuoi=InstrRev(strChuoi,strChuoiTim)
End If
 
End Function

Ứng dụng hàm "Timchuoi"

Trích nguyên văn:
+ Hàm tách tên

Mã:
Function TachTen(Byval strHoTen as String) as String
 TachTen=Mid(strHoTen,Timchuoi(strHoTen," ",False)+1)
End Function
+ Tách tên
Giả sử cột A là Họ và tên. Cần tách tên
Cách 1
=MID(A1,Timchuoi(A1," ",False)+1)
Cách 2
=TachTen(A1)

+ Tách dịch vụ điện thoại di động theo mã số
Giả sử cột A là các số điện thoại 090 4210337; 091 3255126; 098 555444; 0916 066512...
Cần lấy mã dịch vụ
=LEFT(A1,Timchuoi(A1," ")-1)
+ Từ số điện thoại cố định, tách mã vùng
Giả sử cột A là các số điện thoại 04 7544525 08 899655; 051 545222; 020 123456;...

=LEFT(A1,Timchuoi(A1," ")-1)

+ Tách tên tệp ra khỏi đường dẫn

Mã:
'Sử dụng trong môi trương VBE
Sub VD()
Dim strFullPath as String
Dim strFileName as String
 
strFullPath = ActiveWorkbook.FullPath
strFileName=Mid(strFullPath,Timchuoi(strFullPath," \",False)+1)
'Thông báo
Msgbox strFileName,,strFullPath
End Sub


Như vậy chỉ có một hàm "Timchuoi" mà giải quyết được những vấn đề về cắt chuỗi theo các mục đích khác nhau.

Vấn đề tôi muốn nhấn mạnh là chúng ta viết hàm không phải để nó chỉ giải quyết một việc cụ thể mà nó phải giải quyết những bào toán tổng quát. Hàm như một linh kiện máy tính PC có thể lắp vào máy này hay máy khác.

Việc viết hàm và thủ tục còn có rất nhiều các thuật toán hay giúp cho bài toán của bạn được đánh giá ử mức tối ưu. Việc đặt tên cũng vậy còn nhiều trường hợp để đặt khác. Trong phạm vi một bài viết ngắn tôi chỉ có thể đưa ra những lý giải cơ bản và ví dụ nhỏ, các bạn xem và tự tích tũy dần những kiến thức cũng như kinh nghiệm về việc coding.

(Trích bài của anh Nguyễn Duy Tuân)

Một số bài viết có liên quan:
1/ Xếp một trường theo một trật tự màu quy định trước
2/ Hàm để lấy chỉ số màu trong các ô đã Conditional Formatting
3/ Khai báo sử dụng các thành phần đối tượng của Excel
4/ Sử dụng Worksheet Function trong VBA
5/ Hiển thị tiếng việt cho hộp thông báo trong ACCESS & Excel
6/ Khai báo biến và đặt tên biến trong VBA
7/ Hướng dẫn truyền tham số trong VBA (ByVal & ByRef)
8/ UDF hữu ích: Xác định một vùng có tồn tại trong một vùng khác hay không
9/ UDF hữu ích: Một số hàm thông dụng cần thiết
10/ UDF hữu ích: Hàm tìm hàng cuối, cột cuối, ô cuối, ...

http://www.giaiphapexcel.com/vbb/content.php?506
 
Upvote 0
Thanks bạn nha , hướng dẫn khá chi tiết cà dễ hiểu @$@!^%
 
Web KT
Back
Top Bottom