2012-06-05 35 views
10

Esto es probablemente un problema sencillo, pero por desgracia no fue capaz de conseguir los resultados que quería ...Cómo extraer subcadena entre paréntesis utilizando patrón de expresión

decir que tengo la siguiente línea:

"Wouldn't It Be Nice" (B. Wilson/Asher/Love) 

tendría que buscar este patrón:

" (<any string>) 

el fin de recuperar:

B. Wilson/Asher/Love 

Intenté algo así como "" (([^))]*)) pero parece que no funciona. Además, me gustaría utilizar Match.Submatches(0) por lo que podría complicar las cosas un poco porque se basa en soportes ...

+1

Posible duplicado de [Expresión regular a Extraer subcadena] (http://stackoverflow.com/q/1624387/190829) – JimmyPena

Respuesta

17

Editar: Después de examinar el documento, el problema es que hay espacios de no separación antes de los paréntesis, no espacios regulares. Por lo que esta expresión regular debería funcionar: ""[ \xA0]*\(([^)]+)\)

""  'quote (twice to escape) 
[ \xA0]* 'zero or more non-breaking (\xA0) or a regular spaces 
\(  'left parenthesis 
(  'open capturing group 
[^)]+ 'anything not a right parenthesis 
)  'close capturing group 
\)  'right parenthesis 

En función:

Public Function GetStringInParens(search_str As String) 
Dim regEx As New VBScript_RegExp_55.RegExp 
Dim matches 
    GetStringInParens = "" 
    regEx.Pattern = """[ \xA0]*\(([^)]+)\)" 
    regEx.Global = True 
    If regEx.test(search_str) Then 
     Set matches = regEx.Execute(search_str) 
     GetStringInParens = matches(0).SubMatches(0) 
    End If 
End Function 
+0

Es molesto que no parezca funcionar. Probé tu método literal y lo incorporé a mi método ... Realmente parece estar en cuestión con la expresión regular: tan pronto como solo reemplazo la expresión regular por una expresión regular, todo va bien. De todos modos, pensé que podría ser útil darte el archivo .docm exacto que tengo ahora, para que puedas echar un vistazo: http://db.tt/6XoO1Pbn El texto de entrada ya está en el documento. ¡Gracias por adelantado! – Daan

+0

Ver mi edición. Parece que hay espacios sin interrupción en el documento. Eso es lo que nos estaba fastidiando. Espero que funcione para ti ahora. – alan

+0

¡Este definitivamente está funcionando! Me preocupaba el límite correcto, lo que provocaba una discrepancia cuando se menciona un ')' entre paréntesis. Quería proponer que la expresión regular encuentre el último ')' en la línea. Pero luego encontré esta cadena: '' They Called It Rock '' (Lowe, Rockpile, Dave Edmunds) - 3:10 (bonus de un solo lado 45, acreditado como Rockpile, no en LP original) '. Ahí va mi plan :) Por cierto, ')' o ') -' tampoco funcionaría, ya que el guión puede diferir y a veces no hay nada después del ')'. Supongo que esto no se puede mejorar, ¿de acuerdo? – Daan

2

Esta expresión regular un buen

".*\(([^)]*) 

En VBA/VBScript:

Dim myRegExp, ResultString, myMatches, myMatch As Match 
Dim myRegExp As RegExp 
Set myRegExp = New RegExp 
myRegExp.Pattern = """.*\(([^)]*)" 
Set myMatches = myRegExp.Execute(SubjectString) 
If myMatches.Count >= 1 Then 
    Set myMatch = myMatches(0) 
    If myMatch.SubMatches.Count >= 3 Then 
     ResultString = myMatch.SubMatches(3-1) 
    Else 
     ResultString = "" 
    End If 
Else 
    ResultString = "" 
End If 
Esto coincide con

Put Your Head on My Shoulder 

en

"Don't Talk (Put Your Head on My Shoulder)" 

Actualización 1

dejo que el suelta expresiones regulares en su archivo doc y que coincide con lo solicitado. Muy seguro de que la expresión regular está bien. No hablo con fluidez VBA/VBScript, pero supongo que es allí donde va mal.

Si quieres hablar un poco más sobre la expresión regular, me parece bien. No estoy ansioso por comenzar a explorar esta API de VBscript que parece misteriosa.

Teniendo en cuenta la nueva entrada está ajustado a la expresión regular

".*".*\(([^)]*) 

Así que no coincide falsamente (Ponga su cabeza en mi hombro) que aparece dentro de las comillas.

enter image description here

+0

Gracias por su respuesta. Lamentablemente, no parece haber ninguna coincidencia con este patrón. Déjame darte la fuente en la que estoy probando esto: http://tiny.cc/ij3ffw. – Daan

+0

@ KeyMs92 Los ejemplos en esa página web son más claros. Actualicé mi respuesta – buckley

+0

Sí, debería haber dado un mejor ejemplo. Parece mi OP. – Daan

3
No

estrictamente una respuesta a su pregunta, pero a veces, por cosas este sencillo, buen ol' funciones de cadena son menos confuso y más conciso que Regex.

Function BetweenParentheses(s As String) As String 
    BetweenParentheses = Mid(s, InStr(s, "(") + 1, _ 
     InStr(s, ")") - InStr(s, "(") - 1) 
End Function 

Uso:

Debug.Print BetweenParentheses("""Wouldn't It Be Nice"" (B. Wilson/Asher/Love)") 
'B. Wilson/Asher/Love 

EDITAR puntos @alan nuestra que esto coincidirá falsamente el contenido del paréntesis en el título de la canción. Esto se hace fácilmente eludido con una pequeña modificación:

Function BetweenParentheses(s As String) As String 
    Dim iEndQuote As Long 
    Dim iLeftParenthesis As Long 
    Dim iRightParenthesis As Long 

    iEndQuote = InStrRev(s, """") 
    iLeftParenthesis = InStr(iEndQuote, s, "(") 
    iRightParenthesis = InStr(iEndQuote, s, ")") 

    If iLeftParenthesis <> 0 And iRightParenthesis <> 0 Then 
     BetweenParentheses = Mid(s, iLeftParenthesis + 1, _ 
      iRightParenthesis - iLeftParenthesis - 1) 
    End If 
End Function 

Uso:

Debug.Print BetweenParentheses("""Wouldn't It Be Nice"" (B. Wilson/Asher/Love)") 
'B. Wilson/Asher/Love 
Debug.Print BetweenParentheses("""Don't talk (yell)""") 
' returns empty string 

Por supuesto, esto es menos concisa que antes!

+0

Pensé en sugerir esto, también, pero coincide falsamente con "No hablo (ponga la cabeza en mi hombro)" – alan

+0

+1 por sugerir algo distinto al método preferido de OP. – JimmyPena

+0

Sí, aprecio el enfoque diferente. Creo que todavía prefiero Regex. No sé sobre la eficiencia (la velocidad no es mi mayor preocupación) pero me gusta la notación compacta. Mi principal preocupación con este método es que no parece muy específico. El límite izquierdo se establece inicialmente como el último '" 'de la cadena. Si el nombre del artista contiene alguna cita, esto causará problemas. Por lo tanto, prefiero usar' "(' como límite izquierdo. – Daan

0

Esta función trabajaron en su ejemplo de cadena:

Function GetArtist(songMeta As String) As String 
    Dim artist As String 
    ' split string by ")" and take last portion 
    artist = Split(songMeta, "(")(UBound(Split(songMeta, "("))) 
    ' remove closing parenthesis 
    artist = Replace(artist, ")", "") 
End Function 

Ex:

Sub Test() 

    Dim songMeta As String 

    songMeta = """Wouldn't It Be Nice"" (B. Wilson/Asher/Love)" 

    Debug.Print GetArtist(songMeta) 

End Sub 

grabados "B. Wilson/Asher/Love" a la ventana Inmediato.

También resuelve el problema alan mentioned. Ejemplo:

Sub Test() 

    Dim songMeta As String 

    songMeta = """Wouldn't (It Be) Nice"" (B. Wilson/Asher/Love)" 

    Debug.Print GetArtist(songMeta) 

End Sub 

también imprime "B. Wilson/Asher/Love" en la ventana Inmediato. A menos que, por supuesto, los nombres de los artistas también incluyan paréntesis.

+0

Me gusta, pero quiero ser lo más específico posible, así que prefiero usar '" (' – Daan

+0

No veo cómo eso hace la diferencia. ¿Puedes explicarlo? – JimmyPena

0

Creo que necesita un archivo de datos mejor;) Es posible que desee considerar el procesamiento previo del archivo en un archivo temporal para su modificación, de modo que los valores atípicos que no se ajusten a su patrón se modifiquen para que coincidan con su patrón. Le lleva mucho tiempo, pero siempre es difícil cuando un archivo de datos carece de consistencia.

Cuestiones relacionadas