Luyện tập Code VBA: Lọc ký tự trùng nhau trong chuỗi !

Liên hệ QC

HeSanbi

Nam Nhân✨Hiếu Lễ Nghĩa Trí Tín✨
Tham gia
24/2/13
Bài viết
2,382
Được thích
3,535
Giới tính
Nam
Bài viết này dành cho các bạn đang học hoặc đam mê hoặc đang phát triển ứng Excel với VBA.
Nhằm luyện tập, học hỏi và phát triển thêm kỹ năng viết Code VBA với những bài tập đơn giản.

"Lọc ký tự trùng nhau trong chuỗi".
--------------------------------
Bài tập: Viết một hàm lọc chuỗi bất kỳ loại bỏ các ký tự trùng nhau trả về kết quả là một chuỗi chứa các ký tự duy nhất, phân biệt ký tự hoa thường và không phân biệt ký tự hoa thường. Và hãy tối ưu hàm một cách tốt nhất có thể.

Ví dụ:

1. "abcde" => "abcde"
2. "tương tư có tương tự suy tư" => ""tương cóựsuy"
3. "Bài hát: Thanh Xuân Của Tôi (Viral Clip) Ca sĩ: Đan Trường Nhạc Hoa, Lời Việt: Tăng Nhật Tuệ Camera: Kuke Hà - Ngọc Kim Lời bài hát: Cùng nhau ngắm mưa Đoạn đường đón đưa Cười cười nói nói vui như thế Thanh xuân lấp lánh như bụi mưa Cùng nhau đếm sao Một thời huyên náo Giật mình nhìn thời gian đã xoá Thanh xuân như chút gió ngọt ngào Ta đã gặp nhau để nói thương nhau Giữ cho nhau ký ức nhiệm màu Nước mắt có lần ướt khoé mi Cũng chẳng muốn rời tay người Tay cầm tay để nói thương nhau Dẫu mai sau vật đổi sao dời Thương vẫn thương vậy thôi Đừng quên nhé thanh xuân của tôi Tự do hát ca Bụi đường quê nhà Nghiêng nghiêng cánh chim bay trong gió Mưa bay lấp lánh những ngày xanh Thành đô nắng hoa Lòng người băng giá Nhiều lần giật mình trong nước mắt Thanh xuân hôm qua đã nhạt nhoà Ta đã gặp nhau để nói thương nhau Giữ cho nhau kí ức nhiệm màu Nước mắt có lần ướt khoé mi Cũng chẳng muốn rời tay người Tay cầm tay để nói thương nhau Dẫu mai sau vật đổi sao dời Thương vẫn thương vậy thôi Đừng quên nhé thanh xuân của tôi Thương vẫn thương vậy thôi Vì em đó thanh xuân của tôi."​
=> "Bài hát:TanXuâCủô(Vrlp)sĩĐườgNạcHo,LệăậmeKk-ọbùắđóvếxấụMộyêGìãúặểơữýứớầéũẳốDẫổdừqựòềí."​
=> "Bài hát:anXuâCủô(Vrlp)sĩĐườgạo,ệăậmeK-ọùắóếấụộyêìãúặểơữýứớầéũẳốDẫổừqựòềí." (Không phân biệt hoa thường)​

Yêu cầu:
1. Cú pháp phải tối ưu.
2. Bài giải có thể nhiều hàm Sử dụng hàm thuần VBA hoặc thư viện Regular Expressions hoặc một thư viện nào có thể
3. Ưu tiên tốc độ xử lý.

(có hoặc không có giải thích về thuật toán hoặc giải thuật đã sử dụng)



Ứng dụng của hàm: Nhận biết và đếm số ký tự đã sử dụng trong một bài thơ, bài viết, ...
--------------------------------
Mời các bạn tham gia!
 
Lần chỉnh sửa cuối:
Bạn cũng chả học được gì cả, bởi vì như tôi đã nói, "đây là sân chơi của dân xịn":


Người ta để giành năng lượng để chiến đấu, suy diễn những giải thuật ngặt nghèo.
Giả sử như file bài 8 của @batman1 là 1 chuỗi liền thì theo bác code nào trong các code trên là phù hợp?
 
Upvote 0
Giả sử như file bài 8 của @batman1 là 1 chuỗi liền thì theo bác code nào trong các code trên là phù hợp?
Tôi có lý do riêng để không lý giải gì thêm.

Tôi chỉ lấy code của bạn ra là vì giải thuật hoàn toàn không phù hợp. Và tôi e rằng sẽ không ai giải thích cho bạn điểm ấy để có thể học hỏi.
Cách làm ngược lại mà tôi nói (dùng chỉ số mảng) nó cũng giống như Dictionary. Nếu ngôn ngữ khác thì nó sẽ nhanh hơn Dictionary. Nhưng vì VBA phải gọi hàm AscW để tính chỉ số của mỗi ký tự cho nên sẽ chậm đi. Cuối cùng thì là sự chạy đua giữa hàm AscW và hàm hash ký tự của Dictionary.
 
Lần chỉnh sửa cuối:
Upvote 0
Tôi có lý do riêng để không lý giải gì thêm.

Tôi chỉ lấy code của bạn ra là vì giải thuật hoàn toàn không phù hợp. Và tôi e rằng sẽ không ai giải thích cho bạn điểm ấy để có thể học hỏi.
Viết bài cho vui thôi bác ạ, tôi không có cần học hỏi.
Có lẽ bác không giải thích cũng được nhưng mà như vậy tức là bác không bảo vệ được quan điểm của mình.
Vậy đánh giá của bác về code bài 15 đâu có cơ sở.
Bài đã được tự động gộp:

Tôi có lý do riêng để không lý giải gì thêm.

Tôi chỉ lấy code của bạn ra là vì giải thuật hoàn toàn không phù hợp. Và tôi e rằng sẽ không ai giải thích cho bạn điểm ấy để có thể học hỏi.
Cách làm ngược lại mà tôi nói (dùng chỉ số mảng) nó cũng giống như Dictionary. Nếu ngôn ngữ khác thì nó sẽ nhanh hơn Dictionary. Nhưng vì VBA phải gọi hàm AscW để tính chỉ số của mỗi ký tự cho nên sẽ chậm đi. Cuối cùng thì là sự chạy đua giữa hàm AscW và hàm hash ký tự của Dictionary.
Nếu file bài 8 của @batman1 là 1 chuỗi, chiều dài có lẽ phải vài trăm ngàn ký tự.

Nếu quét qua từng ký tự cũng phải vài trăm ngàn lần, trong khi tính theo chỉ số bài 15 chỉ có khoảng vài chục ngàn lần.
Để đánh giá cũng cần có 1 vài con số cụ thể, áng chừng có lẽ không thuyết phục bác ạ.
 
Lần chỉnh sửa cuối:
Upvote 0
Tôi xin lỗi. Tôi ngỡ bạn thích học code thì tôi mách. Nhưng tôi đã chủ quan và đã lầm to.
Về việc cần thuyết phục thì xin miễn. Tôi chỉ dạy học trò chứ không bảo vệ quan điểm.
Tôi thà xếp giáo chịu thua chứ không cố gắng giải thích để được hơn.

Nếu cần xin lỗi chính xác hơn thì cứ cho biết, tôi sẵn sàng trở lại bài #17 để chú thích:
"Tôi chấp nhận lý luận của mình không đủ thuyết phục. Tôi xin rút lại lời phê bình bài #15 và gởi lời xin lỗi chủ code bài #15.
 
Upvote 0
Tôi xin lỗi. Tôi ngỡ bạn thích học code thì tôi mách. Nhưng tôi đã chủ quan và đã lầm to.
Về việc cần thuyết phục thì xin miễn. Tôi chỉ dạy học trò chứ không bảo vệ quan điểm.
Tôi thà xếp giáo chịu thua chứ không cố gắng giải thích để được hơn.

Nếu cần xin lỗi chính xác hơn thì cứ cho biết, tôi sẵn sàng trở lại bài #17 để chú thích:
"Tôi chấp nhận lý luận của mình không đủ thuyết phục. Tôi xin rút lại lời phê bình bài #15 và gởi lời xin lỗi chủ code bài #15.
Có lỗi gì ở đây đâu bác.
Vấn đề ở đây là bảo vệ quan điểm, vậy thôi. Bác không muốn bảo vệ quan điểm mình đã đưa ra thì tùy, không có vấn đề gì ở đây hết cả.
 
Upvote 0
Tôi xin lỗi tất cả 3 chỗ:
1. với bạn, vì tôi đã hiểu lầm
2. với mọi bạn khác, vì tôi đã khơi một câu hỏi mà không có can đảm đi đến câu trả lời.
3. với chính mình, từng trải bao nhiêu năm mà còn chủ quan.
 
Upvote 0
Về giải thuật không kể, nhưng về "sử dụng hàm thư viện" thì Bác có 95% khả năng thua tôi rồi.
Nếu tôi copy code của Bác, và nghe theo lời của anh chàng "viết lại hàm Microsoft" kia. Tôi dùng các hàm thời thượng (Q)BASIC thì cứ mỗi lượt gọi hàm string, tôi nhanh hơn bác vài na-nô giây. :p:p:p
Thế thì bác không đọc các bài của tôi rồi. Tôi đã nói rất rõ: tôi rất muốn tiết kiệm vài giây, thậm chí vài phần nghìn giây. Nhưng tôi không chắt chiu từng nhịp đồng hồ, từng phần nghìn, phần trăm của na nô giây.

Bác về đọc lại tác giả batman1 đi nhé. :D
 
Upvote 0
Hàm CharDuplicatesRE chắc chắn sai. Hãy chạy CharDuplicatesRE và CharDuplicates với dữ liệu lấy từ tập tin của tôi thì thấy 2 kết quả khác nhau. Vậy một trong 2 hàm là sai. Cụ thể hàm sai là CharDuplicatesRE.
Hai hàm hoàn toàn không sai.

Bác batman1 thử xử lý ký tự xuống dòng trước xem sao
 
Upvote 0
Bạn xem video thì thấy A1 sai. Tức CharDuplicatesRE sai.
Sao Bác không Sort rồi hãy so sánh

Ý của Bác là muốn kết quả của hai Hàm phải thật giống nhau, trong khi em viết code hai hàm chứa ký tự như nhau.

Trong Regex thì hàm Replace xử lý theo Group có thứ tự: Text = S & Text
Đơn giản chỉ cần sửa trong CharDuplicates: Left thành Right và Text = S & Text

PHP:
Function CharDuplicates6(ByVal Text As String, _
               Optional ByVal Compare As VBA.VbCompareMethod = VBA.VbCompareMethod.vbBinaryCompare) As String
  Dim K As Long, S As String
  Do Until VBA.Len(Text) <= K
    DoEvents
    S = VBA.Right$(Text, 1)
    Text = S & VBA.Replace$(Text, S, VBA.Constants.vbNullString, , , Compare)
    K = K + 1
  Loop
  CharDuplicates6 = Text
End Function
 
Lần chỉnh sửa cuối:
Upvote 0
Sao Bác không Sort rồi hãy so sánh

Ý của Bác là muốn kết quả của hai Hàm phải thật giống nhau, trong khi em viết code hai hàm chứa ký tự như nhau.

Trong Regex thì hàm Replace xử lý theo Group có thứ tự: Text = S & Text
Đơn giản chỉ cần sửa trong CharDuplicates: Left thành Right và Text = S & Text

PHP:
Function CharDuplicates6(ByVal Text As String, _
               Optional ByVal Compare As VBA.VbCompareMethod = VBA.VbCompareMethod.vbBinaryCompare) As String
  Dim K As Long, S As String
  Do Until VBA.Len(Text) <= K
    DoEvents
    S = VBA.Right$(Text, 1)
    Text = S & VBA.Replace$(Text, S, VBA.Constants.vbNullString, , , Compare)
    K = K + 1
  Loop
  CharDuplicates6 = Text
End Function
Tôi lấy ví dụ không chuẩn.

Tôi không nói tới ông CharDuplicates, vì ông ta là cao thủ rồi. Tôi nói tới ông CharDuplicatesRE cơ.

Bạn đã chạy với dữ liệu vài MB mà tôi đính kèm chưa? Chắc chắn 2 hàm của bạn cho 2 kết quả khác nhau. Không còn là thứ tự nữa mà là khác nhau cả về độ lớn (LEN) 2 kết quả, và cả về các ký tự cụ thể trong 2 kết quả đó.

2 kết quả khác nhau thì ít nhất phải có một ông sai. Và tôi khẳng định là ông CharDuplicatesRE sai.

Tôi đã biết 1 trong các (?) nguyên nhân.

Khi tập tin text copy từ đâu đó thì rất nhiều khi gặp trường hợp ký tự xuống dòng chỉ là Char(10). Mà nói đâu xa, trong Excel sảy ra như cơm bữa.

Thí nghiệm:

- Gõ ở ô E1: ngay mai -> nhấn Alt + Enter để xuống dòng -> gõ tiếp em di

- chạy code
Mã:
Sub test()
Dim text As String, s As String
    text = Range("E1").Value
    s = CharDuplicatesRE(text, True)
    [a1] = s
End Sub

Trong A1 có:

ngy mai
em di


Rõ ràng "m" và "i" xuất hiện 2 lần, tức không duy nhất.

Như thế nếu hàm của bạn lấy dữ liệu nguồn từ các ô trên trang tính Excel có xuống dòng, hoặc lấy từ các tập tin được copy từ web về như tập tin của tôi, thì kết quả sẽ sai.
--------------
Nếu bạn gọi ông CharDuplicates thì ông ta nói: Êêê, với bậc cao thủ như tôi thì không có việc gì khó ... Và ông ta trả về

ngay mi
ed


Tức ông ta mọi text đều chơi tuốt, và làm được, làm chuẩn.
 
Upvote 0
Không biết bác @batman1 đang đề cập đến điều gì.

Đơn giản chỉ cần bác xóa ký tự xuống dòng ở File của bác và xử lý chuỗi là xong.
Xử lý chuỗi thì ký tự xuống dòng cần được xử lý trước.

Ký tự xuống dòng nó là ký tự đặt biệt để con người có thể viết ở một số trường hợp cần thiết. Chứ nó không phải là nhất thiết phải có.

Như viết thơ thì phải xuống dòng để biết rằng thơ có thơ 6-8, 7, ...
Hoặc màn hình có chiều ngang có 1270 pixel nên phải xuống dòng để có thể dễ dàng nhìn được hết câu văn.
Rất nhiều tình huống xuống dòng.

Tuy nhiên ở vấn đề bài viết này, không ai đi hỏi rằng "câu kia có xuống dòng hay không?"

Tình huống File của Bác chỉ cần bỏ đi kí tự xuống dòng sau đó vận dụng hàm.

Bác để ý 3 ví dụ của em nêu ra không có ví dụ nào có xuống dòng cả.

Vấn đề này em chưa đề cập đến trong bài viết.

Việc xử lý xuống dòng là một vấn đề khác nữa.

Chẳn hạn như là "dòng 8 của bài thơ ABC chứa những ký tự nào?"

Do file của Bác đưa ra vào trường hợp bài viết này không phù hợp. Chứ không phải Hàm viết sai.

Em xin gửi Bác file của Bác đã được xử lý loại bỏ xuống dòng để Bác kiểm tra hàm.
 

File đính kèm

  • data.rar
    1.5 MB · Đọc: 22
Lần chỉnh sửa cuối:
Upvote 0
Không biết bác @batman1 đang đề cập đến điều gì.

Đơn giản chỉ cần bác xóa ký tự xuống dòng ở File của bác và xử lý chuỗi là xong.
Xử lý chuỗi thì ký tự xuống dòng cần được xử lý trước.

Ký tự xuống dòng nó là ký tự đặt biệt để con người có thể viết ở một số trường hợp cần thiết. Chứ nó không phải là nhất thiết phải có.

Như viết thơ thì phải xuống dòng để biết rằng thơ có thơ 6-8, 7, ...
Hoặc màn hình có chiều ngang có 1270 pixel nên phải xuống dòng để có thể dễ dàng nhìn được hết câu văn.
Rất nhiều tình huống xuống dòng.

Tuy nhiên ở vấn đề bài viết này, không ai đi hỏi rằng "câu kia có xuống dòng hay không?"

Tình huống File của Bác chỉ cần bỏ đi kí tự xuống dòng sau đó vận dụng hàm.

Bác để ý 3 ví dụ của em nêu ra không có ví dụ nào có xuống dòng cả.

Vấn đề này em chưa đề cập đến trong bài viết.

Việc xử lý xuống dòng là một vấn đề khác nữa.

Chẳn hạn như là "dòng 8 của bài thơ ABC chứa những ký tự nào?"

Do file của Bác đưa ra vào trường hợp bài viết này không phù hợp. Chứ không phải Hàm viết sai.

Em xin gửi Bác file của Bác đã được xử lý loại bỏ xuống dòng để Bác kiểm tra hàm.
Tôi không chỉ nói về tập tin của tôi. Tôi cho vd. về text lấy từ các cell của Excel mà.

1. Xử lý thế nào thì bạn phải xử lý thì mới nói chuyện tiếp được. Mà ở đây tôi nói xử lý code của hàm chứ không phải xử lý dữ liệu đầu vào bởi người dùng.

2. Tôi không dùng hàm của bạn thì tại sao tôi phải xử lý? Tôi chỉ góp ý thôi.

Không ai viết code mà lại bắt người dùng phải xử lý dữ liệu trước khi chạy code cả. Nhất là khi dữ liệu đó hoàn toàn hợp lệ trong Excel. Dữ liệu chỉ có 0A là dữ liệu hàng ngày trên Excel. Bạn muốn người dùng hàm của bạn sau khi đọc dữ liệu từ cell phải xử lý nó trước khi gọi hàm của bạn? Thế nếu người ta không biết xử lý thì sao? Nếu người ta là "cao thủ" thì có lẽ họ sẽ tự viết code chứ không dùng hàm của bạn.

Tôi nói về vấn đề khi mà tập tin có thể chứa 0D0A hoặc chỉ chứa 0A lẫn lộn. Chả nhẽ mỗi tập tin lại kiểm tra rồi mới chạy code? Mà việc sửa hàm là việc của tác giả code chứ không phải việc của người dùng là lại phải viết code xử lý dữ liệu rồi mới gọi hàm của tác giả. Góp ý thôi chứ không ai bắt bạn phải làm gì cả. Bạn mở chủ đề cho cả những người đang học chứ không phải chỉ cho những người đã có mặt trong chủ đề này. Người ta có khi thử chạy code và thấy lỗi như tôi, thì làm sao người ta biết phải viết thêm đoạn code xử lý như thế nào? Hay là bạn muốn người ta mở từng tập tin rồi xử lý bằng tay vụ 0A (nếu có) rồi mới chạy code? Còn nếu bạn mặc định là chỉ có tôi dùng code của bạn, và tôi đủ sức xử lý, thì xin thưa: tôi không có ý định dùng code của bạn.
-----------------------------------------------------------------------------------------------
Về tập tin đính kèm thì không cần thiết. Có mỗi việc "xử lý" mà bạn nghĩ tôi không làm được sao? Tôi góp ý cho code của bạn thôi.
 
Lần chỉnh sửa cuối:
Upvote 0
Web KT
Back
Top Bottom