Как извлечь подстроку в круглых скобках с использованием шаблона Regex

Это, вероятно, простая проблема, но, к сожалению, я не смог получить результаты, которые я хотел...

Скажем, у меня есть следующая строка:

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

Мне пришлось бы искать этот шаблон:

" (<any string>)

Чтобы получить:

B. Wilson/Asher/Love

Я пробовал что-то вроде "" (([^))]*)), но он не работает. Кроме того, я хотел бы использовать Match.Submatches(0), так что это может немного усложнить ситуацию, поскольку оно зависит от скобок...

Ответ 1

Изменить. После изучения вашего документа проблема заключается в том, что перед круглыми скобками, а не с обычными пробелами, есть неразрывные пробелы. Поэтому это регулярное выражение должно работать: ""[ \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

В функции:

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

Ответ 2

Не строго ответ на ваш вопрос, но иногда для вещей эти простые, хорошие функции строковой строки менее запутанны и более кратки, чем Regex.

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

Использование:

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

EDIT @alan указывает, что это будет ложно соответствовать содержимому круглых скобок в названии песни. Это легко обойти с небольшой модификацией:

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

Использование:

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

Конечно, это менее кратким, чем раньше!

Ответ 3

Это хорошее регулярное выражение

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

В 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

Это соответствует

Put Your Head on My Shoulder

в

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

Обновление 1

Я разрешаю регулярному выражению в файле doc, и он соответствует запросу. Совершенно верно, регулярное выражение в порядке. Я не уверен в VBA/VBScript, но я предполагаю, что там, где это происходит неправильно

Если вы хотите обсудить регулярное выражение еще немного, это прекрасно со мной. Я не хочу начинать рыть в этот API VBscript, который выглядит тайным.

С учетом нового ввода регулярное выражение настраивается на

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

Итак, это не ложно соответствует (Положите голову на мое плечо), которое появляется внутри кавычек.

enter image description here

Ответ 4

Эта функция работала над вашей примерной строкой:

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

Пример:

Sub Test()

  Dim songMeta As String

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

  Debug.Print GetArtist(songMeta)

End Sub

печатает "B. Wilson/Asher/Love" в ближайшее окно.

Он также решает проблему alan упомянутую. Пример:

Sub Test()

  Dim songMeta As String

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

  Debug.Print GetArtist(songMeta)

End Sub

также печатает "B. Wilson/Asher/Love" в ближайшее окно. Если, конечно, имена артистов также не включают круглые скобки.

Ответ 5

Я думаю, что вам нужен лучший файл данных;) Возможно, вы захотите рассмотреть предварительную обработку файла в временном файле для модификации, чтобы изменения, не соответствующие вашему шаблону, были изменены так, чтобы они соответствовали вашему шаблону, Это требует много времени, но всегда сложно, когда в файле данных отсутствует согласованность.