Lập trình VBA với Column: chuyển chỉ số cột thành chữ cái (1 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

levanduyet

Hãy để gió cuốn đi.
Thành viên danh dự
Tham gia
30/5/06
Bài viết
1,798
Được thích
4,707
Giới tính
Nam
Đôi khi trong lập trình VBA các bạn cần chuyển số cột sang chữ. Hàm sau sẽ giúp các bạn:

Mã:
Function ColumnLetter(ColumnNumber As Integer) As String
  If ColumnNumber > 26 Then

    ' 1st character:  Subtract 1 to map the characters to 0-25,
    '                 but you don't have to remap back to 1-26
    '                 after the 'Int' operation since columns
    '                 1-26 have no prefix letter

    ' 2nd character:  Subtract 1 to map the characters to 0-25,
    '                 but then must remap back to 1-26 after
    '                 the 'Mod' operation by adding 1 back in
    '                 (included in the '65')

    ColumnLetter = Chr(Int((ColumnNumber - 1) / 26) + 64) & _
                   Chr(((ColumnNumber - 1) Mod 26) + 65)
  Else
    ' Columns A-Z
    ColumnLetter = Chr(ColumnNumber + 64)
  End If
End Function
Sưu tầm

Lê Văn Duyệt
 
Em xin gửi thêm một cách, gọn và dùng được cho cả OF2007.
PHP:
Function StrCol(ColNum As Integer) As String
StrCol = Mid(Cells(1, ColNum).Address, 2, InStr(2, Cells(1, ColNum).Address, "$") - 2)
End Function
 
Upvote 0
Đóng góp thêm gia vị cho bữa tiệc

Mã:
Function StrCol(ColNum As Integer) As String
 Dim Loai0 As Integer
 Loai0 = ColNum Mod 26:              If Loai0 = 0 Then Loai0 = 26
 StrCol = Choose((ColNum - 1) \ 26 + 1, "", "A", "b", "C", "D", "E", "F", "G", "H", "i") _
      & Chr(64 + Loai0)
End Function
 
Lần chỉnh sửa cuối:
Upvote 0
Đôi khi trong lập trình VBA các bạn cần chuyển số cột sang chữ. Hàm sau sẽ giúp các bạn:

Mã:
Function ColumnLetter(ColumnNumber As Integer) As String
  If ColumnNumber > 26 Then

    ' 1st character:  Subtract 1 to map the characters to 0-25,
    '                 but you don't have to remap back to 1-26
    '                 after the 'Int' operation since columns
    '                 1-26 have no prefix letter

    ' 2nd character:  Subtract 1 to map the characters to 0-25,
    '                 but then must remap back to 1-26 after
    '                 the 'Mod' operation by adding 1 back in
    '                 (included in the '65')

    ColumnLetter = Chr(Int((ColumnNumber - 1) / 26) + 64) & _
                   Chr(((ColumnNumber - 1) Mod 26) + 65)
  Else
    ' Columns A-Z
    ColumnLetter = Chr(ColumnNumber + 64)
  End If
End Function
Sưu tầm

Lê Văn Duyệt

Chạy không đúng trong Excel 2007 anh ạ!
 
Upvote 0
Mã:
Function StrCol(ColNum As Integer) As String
 Dim Loai0 As Integer
 Loai0 = ColNum Mod 26:              If Loai0 = 0 Then Loai0 = 26
 StrCol = Choose((ColNum - 1) \ 26 + 1, "", "A", "b", "C", "D", "E", "F", "G", "H", "i") _
      & Chr(64 + Loai0)
End Function

Code của Bác chỉ chạy được với ColNum <= 260
 
Upvote 0
Chủ đề này đã từng nói ít nhất 2 lần trên diển đàn rồi
Giãi pháp dùng công thức:
=SUBSTITUTE(ADDRESS(1,COLUMN(),4),1,"")
Và giãi pháp VBA:
PHP:
Function Coleter(Clls As Range) As String
    Coleter = Replace(Cells(1, Clls.Column).Address(0, 0), 1, "")
End Function
Còn nếu thích kiểu khai báo biến như của Lê Văn Duyệt thì càng dể
PHP:
Function Coleter(ColIndex As Long) As String
    Coleter = Replace(Cells(1, ColIndex).Address(0, 0), 1, "")
End Function
Chắc ăn như bắp---> Chính xác luôn cho Excel2007 với 16384 cột (XFD)
 
Lần chỉnh sửa cuối:
Upvote 0
Chủ đề này đã từng nói ít nhất 2 lần trên diển đàn rồi
Giãi pháp dùng công thức:
Và giãi pháp VBA:
PHP:
Function Coleter(Clls As Range) As String
    Coleter = Replace(Cells(1, Clls.Column).Address(0, 0), 1, "")
End Function
Còn nếu thích kiểu khai báo biến như của Lê Văn Duyệt thì càng dể
PHP:
Function Coleter(ColIndex As Long) As String
    Coleter = Replace(Cells(1, ColIndex).Address(0, 0), 1, "")
End Function
Chắc ăn như bắp---> Chính xác luôn cho Excel2007 với 16384 cột (XFD)


Tuy nhiên vấn đề lấy tên cột làm gì?

Vì nếu đã viết trong VBA thì chúng ta xử lý theo số hay hơn, và tiện lợi hơn ký tự nhiều, đó cũng lý do trong VBA các hàm các phép xử lý liên quan nhận dạng cột đều thể hiện ở số thứ tự.
 
Upvote 0
Cám ơn các bạn đã đưa ra các giải pháp của mình.

Code tôi sưu tầm thì chắc chắn không dùng trong Excel 2007 được, cách của Bác SA cũng thế.

Cách của HoangDanh282vn, ndu96081631 thì dùng được cho Excel 2007. Chúng ta còn cách nào nữa không?

LVD
 
Lần chỉnh sửa cuối:
Upvote 0
Thực ra để làm ra được mục đích như hàm của anh Duyệt mà dùng hàm kết hợp Address của Excel thì quá dễ vì bản thân nó đã tự ra địa chỉ rồi mà :). Nếu chỉ để đạt được mục đích thì cách gì ngắn gọn hiệu quả thì ta dùng.

Em quan tâm cách anh Duyệt đã giới thiệu là không dùng hàm hỗ trợ của Excel, thể hiện thuật giải. Vẫn theo hướng này nếu viết được cho 2007 thì sẽ hay hơn nữa.
 
Lần chỉnh sửa cuối:
Upvote 0
Thực ra để làm ra được mục đích như hàm của anh Duyệt mà dùng hàm kết hợp Address của Excel thì quá dễ vì bản thân nó đã tự ra địa chỉ rồi mà :). Nếu chỉ để đạt được mục đích thì cách gì ngắn gọn hiệu quả thì ta dùng.

Em quan tâm cách anh Duyệt đã giới thiệu là không dùng hàm hỗ trợ của Excel, thể hiện thuật giải. Vẫn theo hướng này nếu viết được cho 2007 thì sẽ hay hơn nữa.
Mình chưa hiểu ý bạn lắm (ngay chổ màu đỏ)...
Mình ngầm hiểu là bạn đang nói đến các hàm trong bảng tính (tức dùng WorkSheetFunction)... nhưng các giãi pháp trình bày từ bài 1 đến cuối mình đâu thấy chổ nào dùng hàm của Excel nhỉ
Tuân có thể nói rõ hơn 1 chút được không!
Cãm ơn!
 
Lần chỉnh sửa cuối:
Upvote 0
Mình chưa hiểu ý bạn lắm (ngay chổ màu đỏ)...
Mình ngầm hiểu là bạn đang nói đến các hàm trong bảng tính (tức dùng WorkSheetFunction)... nhưng các giãi pháp trình bày từ bài 1 đến cuối mình đâu thấy chổ nào dùng hàm của Excel nhỉ
Tuân có thể nói rõ hơn 1 chút được không!
Cãm ơn!

Tức là không dùng tới Range.Address(), Cell.Address() anh ạ, vì Address() hỗ trợ để lấy địa chỉ rồi. Em hiểu ý của tác giả viết hàm ở bai 1 là thể hiện thuật toán. Vấn đề tiếp theo là thuật giải như thế nào để dùng cho cả Excel 2007 với tên cột tối cuối cùng là XFD.

=ColumnLetter(16384) = "XFD"
 
Lần chỉnh sửa cuối:
Upvote 0
Tức là không dùng tới Range.Address(), Cell.Address() anh ạ, vì Address() hỗ trợ để lấy địa chỉ rồi. Em hiểu ý của tác giả viết hàm ở bai 1 là thể hiện thuật toán. Vấn đề tiếp theo là thuật giải như thế nào để dùng cho cả Excel 2007 với tên cột tối cuối cùng là XFD.

=ColumnLetter(16384) = "XFD"
Ai chà... nếu dùng kiểu Convert số thành chử cho giống với Column letter thì.. khó đấy! Với Excel2007, tên cột là 3 ký tự lại càng khó!
Tuy nhiên thuật toán này cũng đáng để lưu ý lắm đây (dùng vào việc khác chứ không phải lấy tên cột)
Nếu vậy ta sẽ ra đề tài: Lấy tên cột tại 1 cell nào đó nhưng bắt buộc không được dùng Address
Thử xem nhé!
(Mời các cao thủ ra tay )
 
Upvote 0
Ý bác Tuân là muốn dùng chữ cái thay cho số thứ tự đây mà, bác tham khảo đoạn code này xem sao
Mã:
Function Num2Text(i As Double) As String
    Dim strRet As String
    Do While i > 0
        strRet = Chr((i Mod 26) + Asc("A") - 1) & strRet
        i = i \ 26
    Loop
    Num2Text = strRet
End Function
 
Upvote 0
Ý bác Tuân là muốn dùng chữ cái thay cho số thứ tự đây mà, bác tham khảo đoạn code này xem sao
Mã:
Function Num2Text(i As Double) As String
    Dim strRet As String
    Do While i > 0
        strRet = Chr((i Mod 26) + Asc("A") - 1) & strRet
        i = i \ 26
    Loop
    Num2Text = strRet
End Function

Phải nói đây cũng là một thuật giải rất hay! Cảm ơn rollover79! Các bác còn có cách nào nữa không?
 
Upvote 0
Vẫn cùng ý tưởng, nhưng em thử chơi đệ qui cái xem sao nhé, lâu lắm rồi ko đụng đến đệ qui.
Mã:
Function Num2Text(i As Double) As String
    If i <= 26 Then
        Num2Text = Chr(i + Asc("A") - 1)
    Else
        Num2Text = Num2Text(i \ 26) & Chr((i Mod 26) + Asc("A") - 1)
    End If
End Function
 
Upvote 0
Kết quả không đúng khi i=26*n
Num2Text(26) > A@
Num2Text(52) > B@
Lỗi tinh vi mà người bắt lỗi còn tinh vi hơn, hình như bác làm nghề tester thì phải, test lỗi này ngôn ngữ chuyên ngành có phải là test biên không bác?
Em xin sửa lại code cho cả 2 phương pháp vòng lặp và đệ qui như sau:
1. Vòng lặp
Mã:
Function Num2Text(i As Double) As String
    Dim strRet As String
    Do While i > 0
        strRet = Chr(((i - 1) Mod 26) + Asc("A")) & strRet
        i = (i - 1) \ 26
    Loop
    Num2Text = strRet
End Function
2. Đệ qui
Mã:
Function Num2Text(i As Double) As String
    If i <= 26 Then
        Num2Text = Chr(i + Asc("A") - 1)
    Else
        Num2Text = Num2Text((i - 1) \ 26) & Chr(((i - 1) Mod 26) + Asc("A"))
    End If
End Function
 
Upvote 0
Lỗi tinh vi mà người bắt lỗi còn tinh vi hơn, hình như bác làm nghề tester thì phải, test lỗi này ngôn ngữ chuyên ngành có phải là test biên không bác?
Vì mình cũng bị lỗi nay không khắc phục được. Trong bài 11 vừa đưa bài lên thì phát hiện lỗi này nên xóa code (nhưng không xóa được bài nên đành để lại tên hàm !).
Bài các bạn đưa lên thì tôi test lỗi này trước.
 
Upvote 0
Vì mình cũng bị lỗi nay không khắc phục được. Trong bài 11 vừa đưa bài lên thì phát hiện lỗi này nên xóa code (nhưng không xóa được bài nên đành để lại tên hàm !).
Bài các bạn đưa lên thì tôi test lỗi này trước.
À ra thế, vậy sao bác không để code rồi comment thêm trường hợp bị lỗi để mọi người cùng tham khảo có hay hơn không? Bài này thì em đã từng làm rồi, nhưng là làm trên Pascal, vậy code sửa lần này không biết có còn vấn đề gì nữa không ạ?
 
Upvote 0
Tôi cũng có 1 cách theo thuật toán hoàn toàn khác: "Chuyển đổi ColIndex từ hệ đếm cơ số 10 sang hệ đếm cơ số 26"
Ai học toán chắc không lạ về thuật toán chuyển đổi này (khỏi cần nhắc)
Tôi xin trình bày sơ lược toàn bộ quá trình tính toán:
1> Xác định ký tự thứ nhất (từ phải qua trái):
Ch3 = Chr(((ColIndex - 1) Mod 26) + 65)
2> Xác định ký tự thứ hai (từ phải qua trái):
Ch2 = Chr(((Int((ColIndex - 1) / 26) - 1) Mod 26) + 65)
3> Xác định ký tự thứ ba (từ phải qua trái):
Ch1 = Chr(((Int((Int((ColIndex - 1) / 26) - 1) / 26) - 1) Mod 26) + 65)
4> Xác định số lượng ký tự tồn tại thật sự:
Ta dùng logarithm cơ số 26 với số ColIndex để xác định số lượng ký tự... Do trong VBA không có Log cơ số 26 nên ta tùy biến bằng công thức:
Temp = Log(ColIndex - (ColIndex - 1) / 26) / Log(26)
Qty = Int(Temp) + 1
Ở đây tôi hình dung chắc chắn sẽ phải dùng logarithm nhưng lại không biết giãi thích thế nào cho các bạn khác hiểu (mong các cao thủ giõi sư phạm giãi thích thêm phần này)
5> Cuối cùng là tính kết quả:
ColLetter = Right(Ch1 & Ch2 & Ch3, Qty)
6> Toàn bộ code:
PHP:
Function ColLetter(ColIndex As Long) As String
  Dim Ch1 As String, Ch2 As String, Ch3 As String
  Dim Qty As Long, Temp As Double
  Ch3 = Chr(((ColIndex - 1) Mod 26) + 65)
  Ch2 = Chr(((Int((ColIndex - 1) / 26) - 1) Mod 26) + 65)
  Ch1 = Chr(((Int((Int((ColIndex - 1) / 26) - 1) / 26) - 1) Mod 26) + 65)
  Temp = Log(ColIndex - (ColIndex - 1) / 26) / Log(26)
  Qty = Int(Temp) + 1
  ColLetter = Right(Ch1 & Ch2 & Ch3, Qty)
End Function
Với cách tính toán trên, cho dù mai này bác Bill có phát triển bảng tính lên đến cở 1 triệu cột thì vẩn tính ra được như thường (Nếu như bác vẩn giữ cách đánh tên cột theo thứ tự như hiện nay)
Bài toán này không chỉ dùng để lấy Column Letter mà còn có thể ứng dụng vào nhiều việc khác (ví dụ đánh MÃ tự động) tùy theo khả năng phát triển của mổi người
Ghi chú: Nếu các bạn cãm thấy dùng hàm Log quá phức tạp thì có thể IF, chẳng hạn:
PHP:
 If ColIndex < 27 then
      Qty = 1
  ElseIf:
    ColIndex < 703 then
     Qty = 2
  Else:
     Qty = 3
 End If
(Tuy nhiên tôi chả bao giờ khoái mấy vụ IF này, trừ những trường hợp bất khả kháng)
Các bạn xem file đính kèm và góp ý thêm nhé (File được xây dựng trên Excel2007 để có thể test với chỉ số cột > 256)
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Với cách tính toán trên, cho dù mai này bác Bill có phát triển bảng tính lên đến cở 1 triệu cột thì vẩn tính ra được như thường (Nếu như bác vẩn giữ cách đánh tên cột theo thứ tự như hiện nay)
Bài toán này không chỉ dùng để lấy Column Letter mà còn có thể ứng dụng vào nhiều việc khác (ví dụ đánh MÃ tự động) tùy theo khả năng phát triển của mổi người
Ghi chú: Nếu các bạn cãm thấy dùng hàm Log quá phức tạp thì có thể IF, chẳng hạn:
PHP:
 If ColIndex < 27 then
      Qty = 1
  ElseIf:
    ColIndex < 703 then
     Qty = 2
  Else:
     Qty = 3
 End If
(Tuy nhiên tôi chả bao giờ khoái mấy vụ IF này, trừ những trường hợp bất khả kháng)
Các bạn xem file đính kèm và góp ý thêm nhé (File được xây dựng trên Excel2007 để có thể test với chỉ số cột > 256)
Bác chơi khó người khác thế, up file xlsm mà không có OFF2007 thì khóc à? Bài toán này giờ đâu còn liên quan đến cột nữa đâu. Không rõ OFF2007 có gì khác không, nhưng ở trên OFF2003 thì code của bác chỉ có thể tối đa 3 ký tự số mà thôi, không nhiều hơn được. Cụ thể nhé, 2 công thức sau sẽ cho ra cùng 1 kết quả
Mã:
=ColLetter(26*26*26)
=ColLetter(26*26*26*26)
Nó đều cho kết quả là YYZ, và những số lớn hơn cũng thế.
(Hình như hạn chế là ở cái Ch3,Ch2,Ch1)
 
Upvote 0
Bác chơi khó người khác thế, up file xlsm mà không có OFF2007 thì khóc à? Bài toán này giờ đâu còn liên quan đến cột nữa đâu. Không rõ OFF2007 có gì khác không, nhưng ở trên OFF2003 thì code của bác chỉ có thể tối đa 3 ký tự số mà thôi, không nhiều hơn được. Cụ thể nhé, 2 công thức sau sẽ cho ra cùng 1 kết quả
Mã:
=ColLetter(26*26*26)
=ColLetter(26*26*26*26)
Nó đều cho kết quả là YYZ, và những số lớn hơn cũng thế.
Thì có code đó mà bạn! Tự đưa vào file là xong mà
Vì hiện tại ta đang xét có 3 ký tự nên tôi làm vậy, nếu thêm nữa thì cứ thêm... Ẹc... Ẹc... (Ch3 hoặc Ch4 hoặc Ch5 gì đó... )
Test thì phải có bằng chứng cụ thể... Mình chỉ nói ColIndex(10000) = "cái gì đó" <--- Ai mà tin, nên đưa file Excel2007 lên chủ yếu để minh họa
quả đúng mấy cái Ch1, Ch2, Ch3 chính là hạn chế (vì trình độ tôi mới tới đó... Thông cãm)
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Tôi cũng có 1 cách theo thuật toán hoàn toàn khác: "Chuyển đổi ColIndex từ hệ đếm cơ số 10 sang hệ đếm cơ số 26"
Lúc đầu, tôi cũng nghĩ đơn giản là bài này có gì khó, chỉ chuyển từ cơ số 10 sang cơ số 26 (với cơ số 26 chữ số không phải là số mà là 26 chữ cái A > Z). Nhưng không phài như vậy !
Cơ số 10: gồm các chữ số : 1 2 3 4 5 6 7 8 9 0
Cơ số 26 (26 chữ cái): gồm các ký tự : A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
Vai trò của số 0 và ký tự Z như nhau.
Sự khác nhau giữa CS26 (26 chữ cái) và tên cột
Số hệ 10​
|
1​
|
10​
|
20​
|
25​
|
26​
|
27​
|
51​
|
52​
|
53​
|
Số hệ 26 (chữ cái)|A|J|T|Y|AZ|AA|AY|BZ|BA|
Tên cột|A|J|T|Y|Z|AA|AY|AZ|BA|
Số hệ 26 <> Tên cột| | | | |AZ<>Z| | |BZ<>AZ| |
 
Upvote 0
Lúc đầu, tôi cũng nghĩ đơn giản là bài này có gì khó, chỉ chuyển từ cơ số 10 sang cơ số 26 (với cơ số 26 chữ số không phải là số mà là 26 chữ cái A > Z). Nhưng không phài như vậy !
Cơ số 10: gồm các chữ số : 1 2 3 4 5 6 7 8 9 0
Cơ số 26 (26 chữ cái): gồm các ký tự : A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
Vai trò của số 0 và ký tự Z như nhau.
Sự khác nhau giữa CS26 (26 chữ cái) và tên cột
Số hệ 10​
|
1​
|
10​
|
20​
|
25​
|
26​
|
27​
|
51​
|
52​
|
53​
|
Số hệ 26 (chữ cái)|A|J|T|Y|AZ|AA|AY|BZ|BA|
Tên cột|A|J|T|Y|Z|AA|AY|AZ|BA|
Số hệ 26 <> Tên cột| | | | |AZ<>Z| | |BZ<>AZ| |
Không phải đâu anh ơi... chuyển sang cơ số 26 thì anh phải xem chử A=0, B=1... Z=25 chứ
Chính vì vậy mà trong code có đoạn ColIndex - 1, mục đích để chuyển dảy số 1,2,... ,26 thành 0,1... ,25
Cơ số 10 thì số 0 nằm đầu tiên, số 9 cuối cùng ... tương tự thế cho tất cả các cơ số
Em thấy rất bình thường, đâu có khó khăn gì chứ
 
Upvote 0
Không phải đâu anh ơi... chuyển sang cơ số 26 thì anh phải xem chử A=0, B=1... Z=25 chứ
Chính vì vậy mà trong code có đoạn ColIndex - 1, mục đích để chuyển dảy số 1,2,... ,26 thành 0,1... ,25
Cơ số 10 thì số 0 nằm đầu tiên, số 9 cuối cùng ... tương tự thế cho tất cả các cơ số
Em thấy rất bình thường, đâu có khó khăn gì chứ
Đúng là thuật toán của các bạn rất hay, gọn và vận dụng được vào bài toán chuyển stt cột thành tên cột. Thuật toán có điểm giống như chuyển cơ số nhưng không phải chuyển cơ số được vì cách chuyển tên cột khi đến bội 26 khác với chuyển cơ số 26.
Nếu là CS10 thì đến 10 là 2 chữ số, CS26 thì đến 26 là 2 chữ số. Nhưng tên cột 26 là Z. Nếu hiểu Z là 25 thì AA là cột thứ mấy khi hiểu A=0 > Z=25?
Có lẽ đi hơi lạc đề. Tôi đặt vấn đề này vì đã dùng hàm chuyển cơ số n sang cơ số m nhưng riêng bài toán này thì sai !
Kết thúc câu hỏi của tôi các bạn nhé !
 
Upvote 0
Đúng là thuật toán của các bạn rất hay, gọn và vận dụng được vào bài toán chuyển stt cột thành tên cột. Thuật toán có điểm giống như chuyển cơ số nhưng không phải chuyển cơ số được vì cách chuyển tên cột khi đến bội 26 khác với chuyển cơ số 26.
Nếu là CS10 thì đến 10 là 2 chữ số, CS26 thì đến 26 là 2 chữ số. Nhưng tên cột 26 là Z. Nếu hiểu Z là 25 thì AA là cột thứ mấy khi hiểu A=0 > Z=25?
Có lẽ đi hơi lạc đề. Tôi đặt vấn đề này vì đã dùng hàm chuyển cơ số n sang cơ số m nhưng riêng bài toán này thì sai !
Kết thúc câu hỏi của tôi các bạn nhé !
Uh.. đúng.. Em nhầm... Nó giống với chuyển đổi cơ số nhưng không phải là chuyển cơ số... Vì nếu đúng thế thì sau A rồi đến B... sau Y rồi đến Z và sau Z phải là BA chứ không phải AA
Cãm ơn anh!
 
Upvote 0
Chính xác quá, Thầy ạ. Em cứ nhìn thuật toán, rồi thử, thấy đúng, nên không để ý tên gọi của phương pháp. Té ra cái học của mình, ẹ quá. bây giờ thì hiểu:
Nếu hiểu Z là 25 thì AA là cột thứ mấy khi hiểu A=0 > Z=25?
BA sẽ là cột 10 theo cơ số 26. Còn AA = A = 0. Hị hị.
 
Upvote 0
Giờ để ý kỹ thấy trò này hao hao giống với hệ đếm BCD: Số 10 của BCD đúng bằng số 10 của hệ thập lục phân, nhưng sau số 9 là nó "nhãy cóc" lên 10 luôn (bỏ qua A, B, C, D, E và F)... Vậy nếu cho rằng thuật toán em làm ở trên là 1 hệ đếm thì nó đã bỏ qua số 0... tương đương A = 1, B = 2 và Z = 26
Nếu đúng thế thì:
AA đổi sang CS10 sẽ là: 1*26^1 + 1*26^0 = 27 ---> OK
Gần giống như khi ta đếm từ 1 đến 9 rồi "nhãy cóc" luôn đến 11 (bỏ qua 10)
Dù sao vẩn thấy cái vụ "đệ quy" gì đó của bạn Rollover79 rất độc chiêu, đơn giãn mà hiệu quả... Xem thuật toán thì hiểu, nhưng nếu nói "đệ quy" thì chẳng hiểu nó nghĩa là cái giống gì
(thổng cãm cho em bé chưa được đến trường)
Ẹc... Ec...
 
Upvote 0
nhưng nếu nói "đệ quy" thì chẳng hiểu nó nghĩa là cái giống gì
(thổng cãm cho em bé chưa được đến trường)
Buồn quá, buồn quá! Đệ quy có giải thích sơ bộ ở đây, bài 132.
http://www.giaiphapexcel.com/forum/showthread.php?t=6354&page=7
Vậy đệ quy là gì?
Các đoạn code khi chuyển sang Function thì gọi là hàm. Nếu trong hàm có dòng lệnh tự gọi chính hàm này ra thực thi lần 2, lần 3, . . . thì gọi là đệ quy.
Trường hợp dùng đệ quy:
Trong quá trình tính toán, sau một vài lệnh ta có 1 kết quả hoặc kết quả tạm đang lưu giữ trong 1 biến nào đó, thí dụ biến Tam.
Ta lại thấy rằng để đi đến kết quả cuối cùng, ta phải dùng lại các câu lệnh trên 1 lần nữa nhưng không phải tính toán trên các tham số ban đầu mà là tính toán trên cái biến Tam này. Vậy ta dùng 1 câu lệnh gọi chính hàm này ra chạy, nhưng tham số lần này của hàm là biến Tam.

Lý thuyết là như vậy nhưng thực sự trong công việc hàng ngày của phần lớn nhân viên công sở, kể cả nhân viên kỹ thuật, cũng ít dùng.

Nói ngắn lại: Đệ quy là phương pháp dùng câu lệnh gọi lại chính mình (function)

Buồn quá, buồn quá! ai nói chưa học thì được chứ ndu ....
 
Upvote 0
Buồn quá, buồn quá! Đệ quy có giải thích sơ bộ ở đây, bài 132.
http://www.giaiphapexcel.com/forum/showthread.php?t=6354&page=7
Buồn quá, buồn quá! ai nói chưa học thì được chứ ndu ....
Em nói thật đấy! Vì em chưa từng bước chân vào đại học, chưa từng học tin học 1 ngày nào cho đến nơi đến chốn nên có cái đã biết nhưng "thuật ngữ" thì có lẽ chưa hề nghe qua bao giờ
Cũng giống như ngày xưa nghe nói Method, Properties... vân vân, chả biết nó là cái giống gì (dù đã có từng xài)
Ý em muốn nói vấn đề "thuật ngữ" đã gây khó khăn không ít cho những tay mới vào nghề như em... Nhiều khi các cao thủ nói 1 câu mà mình nghe giống y như họ đang bàn "đại sự" (biết trời trăng mây nước gì đâu mà hiểu)
 
Upvote 0
Em nói thật đấy! Vì em chưa từng bước chân vào đại học, chưa từng học tin học 1 ngày nào cho đến nơi đến chốn nên có cái đã biết nhưng "thuật ngữ" thì có lẽ chưa hề nghe qua bao giờ
Cũng giống như ngày xưa nghe nói Method, Properties... vân vân, chả biết nó là cái giống gì (dù đã có từng xài)
Ý em muốn nói vấn đề "thuật ngữ" đã gây khó khăn không ít cho những tay mới vào nghề như em... Nhiều khi các cao thủ nói 1 câu mà mình nghe giống y như họ đang bàn "đại sự" (biết trời trăng mây nước gì đâu mà hiểu)

Em cũng như anh thôi, thực sự không biết đệ quy là gì? Nhưng nhìn thuật toán hay quá! Đang nghiên cứu, thực sự chưa hiểu lắm! Cũng phải ráng học thôi! Việc học là vô bờ bến mà. Ẹc ... Ẹc...
 
Upvote 0
Tuy nhiên vấn đề lấy tên cột làm gì?

Vì nếu đã viết trong VBA thì chúng ta xử lý theo số hay hơn, và tiện lợi hơn ký tự nhiều, đó cũng lý do trong VBA các hàm các phép xử lý liên quan nhận dạng cột đều thể hiện ở số thứ tự.

1/ Tất nhiên là ta thường xử lý theo số, nhưng cũng có một số đoạn mã VBA dùng theo địa chỉ nên việc lấy tên cột là cần thiết.
2/ Mấy hàm sử dụng đến Cells... chỉ gọn khi viết trong sheet còn nếu đặt hàm trong Module (khai báo Public để dùng cho nhiều sheet) nếu không nói rõ sẽ hiểu là ActiveSheet do vậy phải khai báo thêm Sh as Object, ... khá là bất tiện
3/ Việc viết hàm ngắn gọn chưa chắc đã chạy nhanh hơn!
Vài lời chia sẻ
Jack NT
 
Upvote 0
Tuy nhiên tôi chả bao giờ khoái mấy vụ IF này, trừ những trường hợp bất khả kháng)
Bài của bác rất hay chỉ xin góp ý chút xíu:
Xem ra có vẻ bác vốn là dân chuyên toán hay dân toán luôn.
Bác không khoái mấy cái IF mà đi xài log có lẽ vì vẻ đẹp của công thức chăng. Nhưng tui lại e là chỉ gọi mỗi chữ log thôi nhưng máy phải chạy nhiều vòng hơn cái IF bác ạ.
 
Upvote 0
Bài của bác rất hay chỉ xin góp ý chút xíu:
Xem ra có vẻ bác vốn là dân chuyên toán hay dân toán luôn.
Bác không khoái mấy cái IF mà đi xài log có lẽ vì vẻ đẹp của công thức chăng. Nhưng tui lại e là chỉ gọi mỗi chữ log thôi nhưng máy phải chạy nhiều vòng hơn cái IF bác ạ.
Bạn nói cũng rất có lý ---> Có điều tôi rất ngại phải viết dài dòng ---> Càng ngắn tôi càng khoái
Còn về tốc độ thì đương nhiên tôi ưu tiên hàng đầu rồi, tuy nhiên chưa có điều kiện test thử ---> Bạn rảnh rồi làm thử 1 bài test xem kết quả thế nào nhé
 
Upvote 0
Góp vui bằng 1 hàm sưu tầm (chắc của Tây):
Mã:
Function ExcelColNonRec(ByVal intCol As Long) As String
    While (intCol > 0)
        intCol = intCol - 1
        ExcelColNonRec = Chr(65 + (intCol Mod 26)) + ExcelColNonRec
        intCol = intCol \ 26
    Wend
End Function

Mình chuyển sang đệ quy để thấy đệ quy bản chất cũng là lặp (lâu rồi nên cũng quên định nghĩa đệ quy)
Mã:
Function ExcelNumberToColumnName(ByVal intCol As Long) As String
    If (intCol > 0) Then
        intCol = intCol - 1
        ExcelNumberToColumnName = ExcelNumberToColumnName(intCol \ 26) + Chr(65 + (intCol Mod 26))
    End If
End Function

Đại diện cho giải thuật đệ quy có lẽ là bài toán tính giai thừa cho dễ hình dung:
Mã:
Function Giaithua(n As Long) As Long
    If n > 1 Then Giaithua = n * Giaithua(n - 1) Else Giaithua = 1
 
Upvote 0
Nhờ các bác chỉ giúp ak, mình có 1 dòng (các ô trên dòng đó chứa giá trị có thể là 1 số hoặc là 1 chuỗi ký tự cố định ko thay đổi) mình muốn xác định gia trị đó đang nằm ở cột nào thì code như thế nào vậy ak.( em cần lấy tên cột vì có thể dữ liệu cột bị thay đổi do chèn cột nên mình ko thể gán vào 1 cột cố định được)
Mong mọi người giúp đỡ
 
Upvote 0
Nhờ các bác chỉ giúp ak, mình có 1 dòng (các ô trên dòng đó chứa giá trị có thể là 1 số hoặc là 1 chuỗi ký tự cố định ko thay đổi) mình muốn xác định gia trị đó đang nằm ở cột nào thì code như thế nào vậy ak.( em cần lấy tên cột vì có thể dữ liệu cột bị thay đổi do chèn cột nên mình ko thể gán vào 1 cột cố định được)
Mong mọi người giúp đỡ
Bạn dùng phương thức Find().Column để lấy số cột rồi chuyển sang tên cột hoặc Find().Address để lấy địa chỉ dạng $C$R rồi tách lấy tên cột bằng hàm Mid và InstrRev
 
Upvote 0
Em không hiểu cái này:
Các hàm UDF trên, khi mà em sửa khai báo biến lên Double hết, nhưng giá trị biến tối đa cũng chỉ là 2147483648 (Long).
Tại sao vậy ạ?
 
Upvote 0
Em không hiểu cái này:
Các hàm UDF trên, khi mà em sửa khai báo biến lên Double hết, nhưng giá trị biến tối đa cũng chỉ là 2147483648 (Long).
Tại sao vậy ạ?
Tôi thì khong hiểu cái này:
Bạn là thành viên lâu năm, nhiều kinh nghiệm, số bài hỏi và trả lời của bạn không ít. Thế mà bạn hỏi một câu không biết đâu mà mò.
các hàm UDF trên là hàm nào, dẫm chứng 1 cái. Bạn sửa như thế nào và test như thế nào? Bạn có biết cách mặc định một hằng số là Double? 123 được mặc định là Integer, 123& là Long.

Chú thích: trong mấy cái hàm tôi xem sơ qua, có mấy cái dùng toán tử \. Đây là toán tử chia số nguyên, khi áp dụng toán tử này, VBA ép kiểu cả hai vế phải trái của \ về kiểu Long. Kết quả trả về là kiểu Long. Vì việc ép kiểu này cho nên sử dung \ với Double rất nguy hiểm:

1695447397880.png

*** Hiểu biết về kiểu dữ liệu của nhiều người trên diễn đàn này chưa đủ để viết những code liên quan đến kiểu. Tôi biết vậy nhưng lười viết bài quá, đợi bạn nào cần thì hỏi.
 
Upvote 0
các hàm UDF trên là hàm nào, dẫm chứng 1 cái
À, các hàm trên là toàn bộ luôn bác ạ, cái này ít trang nên em thử hết các bài, rồi em chuyển hết về Double (nếu có). Và vượt quá số kiểu Long thì bị lỗi.
Bác giải thích ép kiểu của toán tử thì em hiểu rồi.
 
Upvote 0
Thớt này vốn đã dứt trên 12 năm.
Chỉ là bị cái bài #35 vô duyên nó đào mồ, hổi một câu không liên hệ cho nên nố lại nổi lên.

12 năm trước VBA hơi khác chút. Và bối cảnh GPE cũng khác cho nên người ta code khác. Điển hình ngày xưa để lấy ký tự người ta dùng hàm Chr, ngày nay người ta Index chuỗi hằng. Cách phân số ngày xưa được hiểu theo base, bây giờ được hiểu theo phép tính chỉ số mảng nhiều chiều.
Do vậy, Code đời bây giờ gọn hơn nhiều:
(hằng được VBA chứa trực tiếp trong code cho nên rất hiệu quả)

Function TenCot(ByVal soCot As Long) As String
Const BANGCHUCAI = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Do While soCot > 0
TenCot = Mid(BANGCHUCAI, ((soCot - 1) Mod 26) + 1, 1) & TenCot
soCot = (soCot - 1) \ 26
Loop
End Function

Function TenCotDQ(ByVal soCot As Long) As String
Const BANGCHUCAI = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
If soCot <= 0 Then Exit Function
TenCotDQ = TenCotDQ((soCot - 1) \ 26) & Mid(BANGCHUCAI, ((soCot - 1) Mod 26) + 1, 1)
End Function
 
Lần chỉnh sửa cuối:
Upvote 0
Bổ sung về từ ngữ ĐỆ QUY:

Ở không đọc lại mấy bài trước lại thấy có vụ nói chuyện về cụm từ "đệ quy".
Có một bài (bài #29) nói rằng đệ quy là trường hợp hàm/sub gọi lại chính mình. Thực sự giải thích như vậy không sai, nhưng chưa đủ. Đó là tịa sao tôi nói "bổ sung" thay vì "đính chính".

Đệ quy tiếng trong nghề là "recursive". Nghĩa hoàn chỉnh tiếng Việt là "gọi vòng".
1. Nếu Sub/Func gọi lại chính mình thì đúng tên là đệ quy tuyến tính, hoặc đệ quy trực tuyến.
2. Nếu Sub A gọi Sub B, và B gọi lại A; hoặc A gọi B, B gọi C, và C gọi A (đó là tại sao tôi dùng từ gọi vòng) thì đó là đệ quy luân hồi, hoặc hoàn hồi., hỗ tương. Gọi chung là đệ quy phi tuyến (không đi theo đường thẳng). Trường hợp này rất khó và rất hiếm cho nên nếu trong đời chưa gặp code ấy lần nào thì cũng không có gì đáng ngạc nhiên. Chỉ cần biết là nó hoàn toàn lô gic và có thể thực hiện.
 
Lần chỉnh sửa cuối:
Upvote 0

Bài viết mới nhất

Back
Top Bottom