2012-03-30 39 views
7

Estoy escribiendo una macro que toma una lista de nombres que están en formato LDAP y los convierte en Primero, Último (región). Para aquellos de ustedes que no saben lo que se ve como LDAP, es a continuación:Subcadena de Excel VBA

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

En Excel VBA, que no parecen ser capaces de utilizar String.substring (inicio, final). Una búsqueda en Google parece revelar que Mid (cadena, inicio, fin) es la mejor opción. El problema es este: en Mid, el entero para end es la distancia desde el inicio, no la ubicación del índice real del personaje. Esto significa que diferentes tamaños de nombre tendrán diferentes ubicaciones finales y no puedo usar el índice de ")" para encontrar el final de la región. Como todos los nombres comienzan con CN =, puedo encontrar el final de la primera subcadena correctamente, pero no puedo encontrar ")" correctamente porque los nombres son de diferentes longitudes.

que tienen algún código de abajo:

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

¿Alguien sabe de una manera de utilizar en realidad un conjunto de punto final en lugar de un punto final que es tan muchos valores de distancia desde el principio?

Respuesta

10

Ésta es VBA .. no String.substring;)

Esto es más como VB 6 (o cualquiera abajo) .. así que hay que contentarse con la mitad, instr, len (para obtener el total de len una cadena) ... Creo que te perdiste la lenidad para obtener el total de caracteres en una cadena? Si necesita alguna aclaración solo publique un comentario.

edición:

Otro truco rápida ..

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 

Es evidente que el problema es que ya que se necesita una diference para el segundo parámetro, siempre se debe hacer algunos cálculos para ello ...

+0

El número total de caracteres de la cadena no me ayudará. La longitud puede variar en cualquier lado del ")", por lo que no puedo encontrar la ubicación del índice para detener en función de eso. – spassen

+0

puede publicar un ejemplo de la salida que necesita? generalmente tiene que codificar un bucle for para lograr esto – gbianchi

+0

CN = Smith, John (región), OU = Legal, DC = ejemplo, DC = comand debe convertirse en Smith, John (región) – spassen

4

no estoy seguro de que me dieron su pregunta correcta, pero aquí está mi implementación de (esperemos) lo que quiere:

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 

Ilustra el uso de las funciones Split y Mid.

Es una implementación rápida y sucia que sirve solo con fines ilustrativos. Para usarlo en código real, debe agregar varias verificaciones (por ejemplo, que las colecciones kv y parts contengan al menos dos elementos).

UPD: para cubrir dos formatos posibles del campo CN, a saber "last\, first (region)" y "first last (region)" y hacer las cosas un poco menos sucio Me gustaría tener el enfoque de expresiones regulares.

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 
+0

Parece que debería funcionar, pero cuando intento GetName (CN = last \, first (AAA-somewhere), OU = IT, OU = Users, OU = somewhere - aaa, OU = place, DC = aaa, DC = com) Obtengo un subíndice de error fuera de rango en Value = kv (1) en su segunda vez a través del ciclo. – spassen

+0

@spassen, no sabía que podría haber comas (escapado) en el nombre. Esto complicará el código. – Gebb

+0

Realmente lo descubrí. Me olvidé completamente que podía hacer end - start. Ha sido un largo día. Gracias por la ayuda sin embargo. Esa es una función útil para uso futuro. – spassen

2

me gustaría utilizar InStr para encontrar la posición de los tres caracteres que separan los valores y luego utilizar la izquierda/derecha en ellos.

Esto es lo que hackeado muy rápido:

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 

concatenase ellos para conseguir la salida de cadena que desea.

0

El nombre/apellido bit es fácil si se empieza con esto:

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