VBA Excel查找string中的最后一个特定实例
我在excel中有一个string列表,如下所示:
a>b>b>d>c>a a>b>c>d b>b>b>d>d>a
等等
我想从每个string中提取最后一个c或最后一个d,
例如
a>b>b>d>c>a = C a>b>c>d = d b>b>b>d>d>a = d
我将如何使用VBA(或者只是在可能的情况下直接使用excel)?
这里是一个数组公式来做同样的事情。 (改变公式以避免“Eh”培根等级指出的原始问题)
=MID(A1,MAX((MID(A1,ROW(INDIRECT("1:"&LEN(A1))),1)={"c","d"})*ROW(INDIRECT("1:"&LEN(A1)))),1)
在按下enter
同时按住ctrl+shift
进入数组公式。 如果你做得正确,Excel会在你可以在配方栏中看到的公式放置大括号{...}
。
该公式将返回一个#VALUE!
错误,如果在string中既没有c
也没有d
。
编辑:从你的一些意见,你可能想要使用多个单个字符的话,我提出了以下用户定义函数。 它允许你使用任何长度的单词,而且你也不仅限于两个单词 – 你可以使用任意数量的单词。
你会input一个公式,如:
=LastOne(A8,"Charlie","Delta")
要么
=LastOne(A8,$I1:$I2)
其中I1和I2包含你想检查的单词。
单词需要用一个既不是字母也不是数字的分隔符分开。
构造一个正则expression式(正则expression式),它由pipe道分隔的|
单词或短语的列表。 pipe道|
在一个正则expression式中,与一个OR
相同。 正则expression式开始和结束处的\b
表示一个字边界,即数字或字母与非数字或非字母相邻的点,或string的开始或结尾。 因此,实际的分隔符不重要,只要它不是字母或数字。
所有的比赛都放在比赛集合中; 而我们只需要查找比赛中的最后一项。 将有MC.Count
匹配,因为这个计数是零基础,我们减去一个来获得最后一场比赛。 这里是代码:
===========================================
Option Explicit Function LastOne(sSearch As String, ParamArray WordList() As Variant) As String Dim RE As Object, MC As Object Dim sPat As String Dim RNG, C For Each RNG In WordList If IsArray(RNG) Or IsObject(RNG) Then For Each C In RNG sPat = sPat & "|" & C Next C Else sPat = sPat & "|" & RNG End If Next RNG sPat = "\b(?:" & Mid(sPat, 2) & ")\b" Set RE = CreateObject("vbscript.regexp") With RE .Global = True .Pattern = sPat .ignorecase = True If .test(sSearch) = True Then Set MC = .Execute(sSearch) LastOne = MC(MC.Count - 1) End If End With End Function
===========================================
这里是一个示例截图:
请注意,缺lessWordList单词将导致空白单元格。 如果可以的话,可能会产生一个错误。
你可以使用如下的Excel公式
为了有助于解释将从一个字母开始,然后将在最后显示完整的公式。
首先findc的出现次数
= LEN(A1) - LEN(SUBSTITUTE(A1,"c","")
使用这个位置来replace最后一个唯一的字符($作为例子)
=SUBSTITUTE(A1,"c","$",LEN(A1) - LEN(SUBSTITUTE(A1,"c","")))
接下来find这个独特的人物
= FIND("$",SUBSTITUTE(A1,"c","$",LEN(A1) - LEN(SUBSTITUTE(A1,"c",""))))
这给出了最后一个c的位置,现在你可以在中间函数中使用它来返回最后一个c
= MID(A1,FIND("$",SUBSTITUTE(A1,"c","$",LEN(A1) - LEN(SUBSTITUTE(A1,"c","")))),1)
最后要考虑到c和d,用max来带回最后一个
= MID(A1,MAX(IFERROR(FIND("$",SUBSTITUTE(A1,"c","$",LEN(A1) - LEN(SUBSTITUTE(A1,"c","")))),0),IFERROR(FIND("$",SUBSTITUTE(A1,"d","$",LEN(A1) - LEN(SUBSTITUTE(A1,"d","")))),0)),1)
假设c / d只是例子:
?LastEither("b>b>b>d>d>a", "c", "d") d
运用
Function LastEither(testStr As String, find1 As String, find2 As String) As String Dim p1 As Long: p1 = InStrRev(testStr, find1) Dim p2 As Long: p2 = InStrRev(testStr, find2) If (p1 > p2) Then LastEither = find1 ElseIf (p2 > 0) Then LastEither = find2 End If End Function
一般解决scheme
?FindLastMatch("b>b>b>d>d>a>q>ZZ", ">", "c", "d") d ?FindLastMatch("b>b>b>d>d>a>q>ZZ", ">", "c", "d", "q") q ?FindLastMatch("b>b>b>d>d>a>q>ZZ>ppp", ">", "c", "d", "ZZ", "q") ZZ
运用
Function FindLastMatch(testStr As String, delimiter As String, ParamArray findTokens() As Variant) As String Dim tokens() As String, i As Long, j As Long tokens = Split(testStr, delimiter) For i = UBound(tokens) To 0 Step -1 For j = 0 To UBound(findTokens) If tokens(i) = findTokens(j) Then FindLastMatch = tokens(i) Exit Function End If Next Next End Function
在VBA中,您可以使用以下简单的逻辑来执行此操作。
Dim str As String str = "a>b>b>d>c>a" Dim Cet Cet = split(str,">") Dim i as Integer For i= Ubound(Cet) to Lbound(Cet) If Cet(i) = "c" or "d" or "C" or "D" then MsgBox Cet(i) Exit For End if Next i
假定您的string位于单元格A1中,并且没有使用代字符(〜)字符,则可以在工作表中使用以下代码:
=IF(IFERROR(FIND("~",SUBSTITUTE(A1,"c","~",LEN(A1)-LEN(SUBSTITUTE(A1,"c","")))),0)>IFERROR(FIND("~",SUBSTITUTE(A1,"d","~",LEN(A1)-LEN(SUBSTITUTE(A1,"d","")))),0),"c","d")
编辑:
在回应评论时,下面是对这个如何工作的解释。 我也稍微回顾了一下这个公式。 c
和d
的两个公式是相同的,所以两者的解释都适用。 所以,向外工作
LEN(A1)-LEN(SUBSTITUTE(A1,"c",""))
这里我们从string中删除c
所有实例。 通过比较计算的string和原始string的长度,我们计算出现在原始string中的次数。
SUBSTITUTE(A1,"c","~",LEN(A1)-LEN(SUBSTITUTE(A1,"c","")))
现在我们知道c
出现在string中的次数,我们用波浪字符replacec
的最后一个出现(这里我们假设在string中没有使用波形符号)。
FIND("~",SUBSTITUTE(A1,"c","~",LEN(A1)-LEN(SUBSTITUTE(A1,"c",""))))
然后我们在string中find代字符的位置,这相当于string中最后一个c
的位置。
IFERROR(FIND("~",SUBSTITUTE(A1,"c","~",LEN(A1)-LEN(SUBSTITUTE(A1,"c","")))),0)
在IFERROR
包装这个确保我们没有通过公式的错误 – 如果不存在c
则将值设置为0,以确保如果我们的string包含c
但不包含d
(反之亦然),我们仍然得到正确的答案。
然后,我们对d
应用相同的计算,并比较两者,看看哪一个会出现在我们的string中。 注意:如果string中既没有c
也没有d
,这将给出不正确的答案。