Excel VBA子串

我正在编写一个macros,它采用LDAP格式的名称列表将其转换为First,Last(region)。 对于那些不知道LDAP是什么样子的人来说,下面是:

CN=John Smith (region),OU=Legal,DC=example,DC=comand 

在Excel VBA中,我似乎无法使用string.substring(start,end)。 谷歌search似乎显示,中(string,开始,结束)是最好的select。 问题是这样的:在Mid中,end的整数是从开始的距离,而不是字符的实际索引位置。 这意味着不同的名字大小将有不同的结束位置,我不能使用“)”索引来查找区域的结尾。 由于所有的名字都以CN =开头,所以我可以正确地find第一个子string的结尾,但是我找不到“)”,因为名字长短不一。

我有一些代码如下:

 mgrSub1 = Mid(mgrVal, InStr(1, mgrVal, "=") + 1, InStr(1, mgrVal, "\") - 4) mgrSub2 = Mid(mgrVal, InStr(1, mgrVal, ","), InStr(1, mgrVal, ")") - 10) manager = mgrSub1 & mgrSub2 

有没有人知道一个方法来实际使用一个设定的终点,而不是一个终点,是从开始的那么多值?

这是vba ..没有string.substring;)

这更像是VB 6(或下面的任何一个)..所以你坚持与中,instr,len(获得一个string的总len)..我想你错过了len得到string中的字符总数? 如果您需要澄清,只需发表评论。

编辑:

另一个快速入侵

  Dim t As String t = "CN=Smith, John (region),OU=Legal,DC=example,DC=comand" Dim s1 As String Dim textstart As Integer Dim textend As Integer textstart = InStr(1, t, "CN=", vbTextCompare) + 3 textend = InStr(1, t, "(", vbTextCompare) s1 = Mid(t, textstart, textend - textstart) MsgBox s1 textstart = InStr(1, t, "(", vbTextCompare) + 1 textend = InStr(1, t, ")", vbTextCompare) s2 = Mid(t, textstart, textend - textstart) MsgBox s2 

显然你的问题是,因为你需要一个不同的第二个参数,你应该总是为它做一些math…

我不确定我的问题是否正确,但是这里是我的实现(希望)你想要什么:

 Function GetName(arg As String) As String parts = Split(arg, ",") For Each p In parts kv = Split(p, "=") Key = kv(0) Value = kv(1) If Key = "CN" Then commonName = Value End If Next p regIndex = InStr(1, commonName, "(") region = Mid(commonName, regIndex, Len(commonName) - regIndex + 1) parts = Split(commonName, " ") first = parts(0) last = parts(1) GetName = first & ", " & last & " " & region End Function Sub test() 'Prints "John, Smith (region)" Debug.Print GetName("CN=John Smith (region),OU=Legal,DC=example,DC=comand") End Sub 

它演示了SplitMid函数的使用。

这是一个快速而肮脏的实现,仅用于说明目的。 要在真实的代码中使用它,你需要添加几个检查(例如, kvparts集合包含至less两个元素)。

UPD:为了覆盖CN字段的两种可能的格式,即"last\, first (region)""first last (region)"并且使事情不那么混乱,我会采用正则expression式的方法。

 Function GetName(arg As String) As String Dim RE As Object, REMatches As Object Set RE = CreateObject("vbscript.regexp") With RE .MultiLine = False .Global = False .IgnoreCase = True .Pattern = "CN=(\w+)\s*?(\\,)?.*?," End With Set REMatches = RE.Execute(arg) If REMatches.Count < 1 Then GetName = "" Return End If cn = REMatches(0).Value withComma = (InStr(1, cn, "\,") > 0) If withComma Then lastIndex = 0 firstIndex = 2 regionIndex = 3 patt = "(\w+)\s*?(\\,)?\s*?(\w+)\s*(\(.*?\))" Else lastIndex = 1 firstIndex = 0 regionIndex = 2 patt = "(\w+)\s*?(\w+)\s*(\(.*?\))" End If Set RE = CreateObject("vbscript.regexp") With RE .MultiLine = False .Global = False .IgnoreCase = True .Pattern = patt End With Set REMatches = RE.Execute(arg) If REMatches.Count < 1 Then GetName = "" Return End If Set m = REMatches(0) first = m.SubMatches(firstIndex) last = m.SubMatches(lastIndex) region = m.SubMatches(regionIndex) GetName = first & ", " & last & " " & region End Function Sub test() ' Prints "first, last (AAA-somewhere)" two times. Debug.Print GetName("CN=last\, first (AAA-somewhere),OU=IT,OU=Users,OU=somewhere - aaa,OU=place,DC=aaa,DC=com") Debug.Print GetName("CN=first last (AAA-somewhere),OU=IT,OU=Users,OU=somewhere - aaa,OU=place,DC=aaa,DC=com") End Sub 

我将使用InStr来查找分隔值的三个字符的位置,然后使用左/右。

这就是我真正快速入侵的东西:

 Dim tmp, new_string, first, last, region As String tmp = "CN=John Smith (region),OU=Legal,DC=example,DC=comand" new_string = Right(tmp, Len(tmp) - 3) ' John Smith (region),OU=Legal,DC=example,DC=comand new_string = Left(new_string, (InStr(1, new_string, ",") - 2)) ' John Smith (region) region = Right(new_string, Len(new_string) - InStr(1, new_string, "(")) ' region new_string = Left(new_string, (InStr(1, new_string, "(") - 2)) ' John Smith last = Right(new_string, Len(new_string) - InStr(1, new_string, " ")) ' Smith first = Left(new_string, (InStr(1, new_string, " ") - 1)) ' John 

然后连接它们以获得所需的string输出。

如果您以此开始,名字的第一位/最后一位很容易:

 MsgBox Split(Mid$(sLDAP, 4), ")")(0) & ")"