第一种解决方案是使用一个字典来获得独特的段列表。 它随后将被作为分裂段之前跳过第一地址数作为简单:
Function RemoveDuplicates1(text As String) As String
Static dict As Object
If dict Is Nothing Then
Set dict = CreateObject("Scripting.Dictionary")
dict.CompareMode = 1 ' set the case sensitivity to All
Else
dict.RemoveAll
End If
' Get the position just after the address number
Dim c&, istart&, segment
For istart = 1 To Len(text)
c = Asc(Mid$(text, istart, 1))
If (c < 48 Or c > 57) And c <> 32 Then Exit For ' if not [0-9 ]
Next
' Split the segments and add each one of them to the dictionary. No need to keep
' a reference to each segment since the keys are returned by order of insertion.
For Each segment In Split(Mid$(text, istart), ",")
If Len(segment) Then dict(segment) = Empty
Next
' Return the address number and the segments by joining the keys
RemoveDuplicates1 = Mid$(text, 1, istart - 1) & Join(dict.keys(), ",")
End Function
第二种解决方案将是,以提取所有的段,然后搜索如果它们中的每一个存在于先前的位置是:
Function RemoveDuplicates2(text As String) As String
Dim c&, segments$, segment$, length&, ifirst&, istart&, iend&
' Get the position just after the address number
For ifirst = 1 To Len(text)
c = Asc(Mid$(text, ifirst, 1))
If (c < 48 Or c > 57) And c <> 32 Then Exit For ' if not [0-9 ]
Next
' Get the segments without the address number and add a leading/trailing comma
segments = "," & Mid$(text, ifirst) & ","
istart = 1
' iterate each segment
Do While istart < Len(segments)
' Get the next segment position
iend = InStr(istart + 1, segments, ",") - 1 And &HFFFFFF
If iend - istart Then
' Get the segment
segment = Mid$(segments, istart, iend - istart + 2)
' Rewrite the segment if not present at a previous position
If InStr(1, segments, segment, vbTextCompare) = istart Then
Mid$(segments, length + 1) = segment
length = length + Len(segment) - 1
End If
End If
istart = iend + 1
Loop
' Return the address number and the segments
RemoveDuplicates2 = Mid$(text, 1, ifirst - 1) & Mid$(segments, 2, length - 1)
End Function
和第三解决方案将是使用正则表达式来除去所有的重复链段:
Function RemoveDuplicates3(ByVal text As String) As String
Static re As Object
If re Is Nothing Then
Set re = CreateObject("VBScript.RegExp")
re.Global = True
re.IgnoreCase = True
' Match any duplicated segment separated by a comma.
' The first segment is compared without the first digits.
re.Pattern = "((^\d* *|,)([^,]+)(?=,).*),\3?(?=,|$)"
End If
' Remove each matching segment
Do While re.test(text)
text = re.Replace(text, "$1")
Loop
RemoveDuplicates3 = text
End Function
这些都是对于10000次迭代(越低越好),执行时间:
input text : "123 abc,,1 abc,abc 2,ABC,abc,a,c"
output text : "123 abc,1 abc,abc 2,a,c"
RemoveDuplicates1 (dictionary) : 718 ms
RemoveDuplicates2 (text search) : 219 ms
RemoveDuplicates3 (regex) : 1469 ms
一个RegExp与反向引用将是另一个可能的选择 – brettdj