Как извлечь подстроку в скобках с помощью шаблона 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, который выглядит загадочным.
учитывая новый ввод, регулярное выражение настраивается на
".*".*\(([^)]*)
чтобы он не ложно совпадал (положите голову на мое плечо), который появляется внутри кавычек.
эта функция работала на вашем примере строки:
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" в ближайшем окне. Если, конечно, имена художников также не включают скобки.
Я думаю, вам нужен лучший файл данных ;) вы можете рассмотреть возможность предварительной обработки файла во временный файл для изменения, так что выбросы, которые не соответствуют вашему шаблону, изменяются туда, где они будут соответствовать вашему шаблону. Это занимает много времени, но это всегда сложно, когда файл данных не имеет согласованности.