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

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

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

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

Я должен был бы искать этот шаблон:

" (<any string>)

для того, чтобы получить:

B. Wilson/Asher/Love

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

5 ответов


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

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

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

редактировать @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

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


это хороший regex

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

в 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


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

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

печатает "B. Wilson / Asher / Love" к немедленному окну.

Это также решает проблему alan указано. Ex:

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" в ближайшем окне. Если, конечно, имена художников также не включают скобки.


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