Cách loại bỏ những kí tự trùng nhau.
Làm ơn giúp mình giải quyết vần đề sau nhé.
Mình có các dòng như sau :
FGFG
FC1JFC1J
WUWU
FL,FC,FGFL,FC,FGLàm thế nào để có kết quả :
FG
FC1J
FL,FC,FG
Cái này phải dùng code bạn à!
Cái này phải dùng code bạn à!
Function StrUnique(Text As String) As String
Dim i As Long, Temp
On Error Resume Next
If InStr(Text, ",") Then
Temp = Split(Text, ",")
With CreateObject("Scripting.Dictionary")
For i = 0 To UBound(Temp)
.Add Temp(i), ""
Next i
StrUnique = Join(.Keys, ",")
End With
Else
StrUnique = Left(Text, 1)
For i = 1 To Len(Text)
If InStr(StrUnique, Mid(Text, i, 1)) = 0 Then StrUnique = StrUnique & Mid(Text, i, 1)
Next i
End If
End Functionn
www.giaiphapexcel.com/diendan/threads/c%C3%A1ch-lo%E1%BA%A1i-b%E1%BB%8F-nh%E1%BB%AFng-k%C3%AD-t%E1%BB%B1-tr%C3%B9ng-nhau.33739/post-224312
Hay quá ! Có cách nào cho nó không phân biệt chữ hoa và thường không Thầy ?
VD: DDDDDdddd -> là D hoặc d
Code đâu tiên có sai sót (do tôi không đọc kỹ yêu cầu) —> Đã sửa lại!
Vụ không phân biết HOA thường dể mà —> Ta dùng UCase biến Text thành hoa tất, sau đó mới xử lý tiếp
Nếu dữ liệu thật sự giống như những gì tác giả đưa lên (tức dữ liệu không phải là tiếng Việt có dấu) thì tôi còn có 1 chiêu khác cực ngắn
Function StrUnique(Text As String) As String
Dim i As Long, Temp
Temp = IIf(InStr(Text, ","), Split(Text, ","), Split(StrConv(Text, 64), Chr(0)))
With CreateObject("Scripting.Dictionary")
For i = 0 To UBound(Temp)
If Not .Exists(Temp(i)) Then .Add Temp(i), ""
Next i
StrUnique = Join(.Keys, IIf(InStr(Text, ","), ",", ""))
End With
End Function
Split(StrConv(Text, 64), Chr(0)) dùng để biến 1 chuổi thành 1 mãng với các phần tử chính là từng ký tự của chuổi
Thử cách này xem. Sẽ rút gọn được số lần duyệt của vòng lặp. Tốc độ sẽ được cải thiện.
Function MyFunction(str As String) As String
Do Until i = Len(str)
i = i + 1
str = Left(str, i) & Replace(Right(str, Len(str) – i), Mid(str, i, 1), "")
Loop
MyFunction = str
End Function
Vậy là bạn không xem kỹ yêu cầu rồi
Chuổi FL,FC,FG,FL,FC,FG sau khi qua UDF sẽ cho kết quả là FL,FC,FG chứ không phải FL,CG
Vả lại, xét về tốc độ thì vẫn thế, đằng nào cũng phải duyệt từ 1 đến Len(Chuổi), chẳng thể bớt hơn nữa, nên không thể nói rằng tốc độ đã cải thiện được
Có lẽ bạn chưa hiểu thuật toán trong code của tôi. Bạn xem như thế nào mà bảo là duyệt từ 1 đến Len(Chuỗi) nhỉ??? Code của tôi chỉ duyệt qua số lần là số ký tự duy nhất trong chuỗi. "aaaaaaa" -> duyệt 1 lần, "abaaababaab" -> duyệt 2 lần.
Còn dấu phẩy (,) khắc phục không khó.
Vâng! Giải thuật Replace này hoàn toàn chính xác
Lở rồi, bạn làm luôn vụ dấu phẩy đi cho mọi người học hỏi với nhé!
(Tôi vẫn chưa nghĩ ra)
Function MyFunction(Str As String, Optional C As String = "") As String
If C = "" Then
Do Until i = Len(Str)
i = i + 1
Str = Left(Str, i) & Replace(Right(Str, Len(Str) – i), Mid(Str, i, 1), "")
Loop
MyFunction = Str
Else
Dim IStr As String
Str = C & Replace(Str, C, C & C) & C
Do Until i = Len(Str)
IStr = Mid(Str, i + 1, InStr(Mid(Str, i + 2), C) + 1)
i = i + Len(IStr)
Str = Left(Str, i) & Replace(Right(Str, Len(Str) – i), IStr, "")
Loop
MyFunction = Mid(Replace(Str, C & C, C), 2, Len(Replace(Str, C & C, C)) – 2)
End If
End Function
Chưa được bạn à!
Thử với text này:
Tu–an–tri–Tu–an
Với dấu phân cách là —
Nó cho kết quả là -Tu–antr
Mà lý ra phải là Tu–an–tri
Các giải thuật sử dụng hàm Replace đều phải hết sức cẩn thận, nếu không sẽ bị nhầm ngay!
Trích lọc duy nhất tôi nghĩ dùng Dictionary Object là chắc ăn như bắp —-> Không bao giờ có chuyện nhầm (mà việc dùng code lại cực đơn giản)
Tôi không nghĩ vấn đề này gây khó khăn cho bạn. Đơn giản chỉ cần chuyển dấu phân cách về một kí tự đặc biệt nào đó là xong thôi mà.
Tất cả chúng ta tham gia diễn đàn này đều với mục đích trao đổi và học hỏi nên tôi nghĩ đơn giản chưa phải là tốt. Mà ngược lại, thuật toán càng lạ tôi lại càng thích.
Function MyFunction(Str As String, Optional K As String = "") As String
Dim IStr As String, C As String
Str = Join(IIf(K = "", Split(StrConv(Str, 64), Chr(0)), Split(Str, K)), vbBack)
C = vbBack
Str = C & Replace(Str, C, C & C) & C
Do Until i = Len(Str)
IStr = Mid(Str, i + 1, InStr(Mid(Str, i + 2), C) + 1)
i = i + Len(IStr)
Str = Left(Str, i) & IIf(IStr = C & C, Right(Str, Len(Str) – i), Replace(Right(Str, Len(Str) – i), IStr, ""))
Loop
MsgBox Str
MyFunction = Mid(Replace(Str, C & C, K), 2, Len(Replace(Str, C & C, K)) – 2)
End Function
Ẹc… Ẹc…. Mình cũng rất khoái những cái gì gọi là LẠ và thử thách mình trong những tình huống có độ khó cao
Bạn hãy thí nghiệm code mình trong ví dụ này nhé:
– Cell A1 chứa Text -n-d-u-n-d-u–
– Dấu phân cách là dấu –
– Kết quả mong nhận được là n-d-u (chứ không phải là □n-d-u-)
Ngoài ra: Bạn dùng StrConv cho bài này càng sai nặng!
Trong mục đố vui về VBA có lần tôi đã đề cập rồi, hàm này chỉ dùng để convert chuổi thành mãng trong trường hợp chuổi không được chứa ký tự tiếng Việt Unicode —> Code tôi đưa ở bài trên có dùng hàm này cũng chỉ mang tính tham khảo —> Sao bạn không dùng Replace như bài trước nhỉ?
————————————
Có thời gian rảnh xin bạn cải tiến lại!
Tình huống vừa nêu trên, nếu dùng Dictionary Object lại chẳng ảnh hưởng gì
Chẳng hạn:
Temp = Split(Text, Sep)
With CreateObject("Scripting.Dictionary")
For i = 0 To UBound(Temp)
If Not .Exists(Temp(i)) And Temp(i) <> "" Then .Add Temp(i), ""
Next i
StrUnique = Join(.Keys, Sep)
End With————————————
Nói riêng với bạn:
– Giải thuật lọc chuổi duy nhất trong trường hợp không có dấu phân cách như bạn đã làm, tôi công nhận đấy là ĐỘC ĐÁO (dùng Replace rất sáng tạo)
– Trường hợp có dấu phân cách thì.. ẹc… ẹc… tôi cho rằng bạn hơi cố chấp (thuật toán rườm rà và không có độ chính xác cao)
Tôi dùng StrConv là để gom 2 trường hợp lại làm một cho code gọn thôi. Còn ai muốn dùng cho tiếng Việt thì cứ tách như code cũ thôi.
Nếu bạn nói như vậy thì tôi sửa lại như thế này vậy.
Function MyFunction(Str As String, Optional K As String = "") As String
Dim IStr As String, C As String
Str = Replace(Replace(Application.WorksheetFunction.Trim(Replace(Replace(Str, " ", vbBack), K, " ")), " ", K), vbBack, " ")
Str = Join(IIf(K = "", Split(StrConv(Str, 64), Chr(0)), Split(Str, K)), vbBack)
C = vbBack
Str = C & Replace(Str, C, C & C) & C
Do Until i = Len(Str)
IStr = Mid(Str, i + 1, InStr(Mid(Str, i + 2), C) + 1)
i = i + Len(IStr)
Str = Left(Str, i) & IIf(IStr = C & C, Right(Str, Len(Str) – i), Replace(Right(Str, Len(Str) – i), IStr, ""))
Loop
MyFunction = Mid(Replace(Str, C & C, C), 2, Len(Replace(Str, C & C, C)) – 2)
MyFunction = Replace(MyFunction, C, K)
End FunctionTôi không nói dùng Dictionary Object có gì sai trong trường hợp này cả. Giải thuật của tôi cũng chỉ là một trong nhiều phương án để tác giả và mọi người tham khảo thôi. Đúng hay sai không quan trọng, quan trọng là có thể áp dụng được những gì đọc được từ topic này vào mục đích riêng của từng người một cách hợp lý hay không mới là quan trọng.
Học Nhân sự Tổng hợp – Trở thành chiến binh nhân sự vững nghiệp vụ
Con người là một trong những yếu tố quan trọng của công ty, là tài sản quý giá của doanh nghiệp. Chính vì thế,...
Xem khóa học
Bạn có thể dùng hàm này:
Option Explicit
Function loc(ch As String) As String
Dim Kt
ch = Trim(ch)
Do
Kt = Left(ch, 1)
If InStr(2, ch, Kt) = 0 Then loc = loc & Kt
ch = Replace(ch, Kt, "")
Loop Until Len(ch) = 0
End Function
P/s: Chú ý nên mở chủ đề riêng chứ không chen ngang vào bài của người khác
Bạn viết thế này thì có thể bạn chưa biết lỗi bị xoá bài rồi. Mình nhắc lại để bạn thấy : Cả bài của bạn có dấu tiếng Việt nhưng tiêu đề lại không dấu tiếng Việt. Mình cũng đã đề nghị các Mod lui hạn xoá cho bạn vì bạn mới tham gia có 4 bài nhưng tiếc rằng bạn không sửa. Bạn phải thông cảm vì diễn đàn ngày càng đông thành viên mà nội quy không nghiêm sao được?
Làm được, nhưng bạn phải liệt kê ra cho mọi người biết những dấu nào bạn cho là dấu phân cách
Trong ví dụ trên thì dấu cách và phẩy là dấu phân cách —> Trong file của bạn còn dấu nào được xem là dấu phân cách nữa không? (chẳng hạn là dấu -, dấu _, dấu &… vân vân..)
Đây là hàm mình cũng chưa làm thủ tục tinh chỉnh phần thân chuỗi:
Tranh thủ viết xong giờ lại thấy đổi yêu cầu, mình sẽ làm lại sau vì giờ tan sở rồi.
Em thì làm vầy:
Function SingleChar(Text As String) As String
Dim i As Long, iCount As Long, k As Long
Dim TmpStr As String, Sep As String, Temp, Item, Arr()
If InStr(Text, " ") Then Sep = " "
If InStr(Text, ",") Then Sep = ","
Temp = Split(Text, Sep)
For Each Item In Temp
TmpStr = CStr(Item)
For i = 1 To Len(CStr(Item))
iCount = Len(Text) – Len(Replace(Text, Mid(CStr(Item), i, 1), ""))
If iCount > 1 Then TmpStr = Replace(TmpStr, Mid(CStr(Item), i, 1), "")
Next i
If TmpStr <> "" Then
ReDim Preserve Arr(k)
Arr(k) = TmpStr: k = k + 1
End If
Next Item
SingleChar = Join(Arr, Sep)
End Function
Giảm bớt được 1 vòng lập
Nhưng em còn đang phân vân, không biết trên thực tế có tồn tại cùng 1 lúc 2 dấu phân cách trong 1 chuổi hay không? Nếu có thì… Ẹc.. Ẹc.. tính cũng hơi mệt
Cái gì cũng.. có thể làm được (miễn nó không vô lý)
Tôi đề nghị thế này:
– Bạn giả lập 1 file, trong đó cột A bạn liệt kê 1 số chuổi (khoảng 10 đến 20 dòng với nhiều trường hợp khác nhau)
– Cột B bạn ghi kết quả mà bạn muốn đạt được
– Gữi file lên đây!
Thấy đơn giản vậy mà cũng khó nhai —> Vấn đề ở chổ làm sao COUNTIF các phần tử trong 1 Array (trong khi hàm COUNTIF chỉ làm với Range)
Thôi thì tạo 2 hàm vậy:
Function ArrayCountIf(SrcArray, CriteriaValue)
Dim iCount As Long, Item
For Each Item In SrcArray
If Item = CriteriaValue Then iCount = iCount + 1
Next
ArrayCountIf = iCount
End Function
Function SingleChar(Text As String) As String
Dim k As Long, Sep As String, Temp, Item, Arr()
If InStr(Text, " ") Then Sep = " "
If InStr(Text, ",") Then Sep = ","
Temp = Split(Text, Sep)
For Each Item In Temp
If ArrayCountIf(Temp, Item) = 1 Then
ReDim Preserve Arr(k)
Arr(k) = Item: k = k + 1
End If
Next Item
SingleChar = Join(Arr, Sep)
End FunctionCông thức tại cell B3 là =SingleChar(A3)