【问题标题】:How to extract substring in parentheses using Regex pattern如何使用正则表达式模式提取括号中的子字符串
【发布时间】:2012-06-09 19:55:17
【问题描述】:

这可能是一个简单的问题,但不幸的是我无法得到我想要的结果......

说,我有以下行:

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

我将不得不寻找这种模式:

" (<any string>)

为了检索:

B. Wilson/Asher/Love

我尝试了类似"" (([^))]*)) 的方法,但它似乎不起作用。另外,我想使用Match.Submatches(0),这样可能会使事情变得复杂一些,因为它依赖于括号......

【问题讨论】:

标签: regex vba substring


【解决方案1】:

这是另一个用 vbscript (?:\()(.*)(?:\)) Demo Here 测试的正则表达式


Data = """Wouldn't It Be Nice"" (B. Wilson/Asher/Love)"
wscript.echo Extract(Data)
'---------------------------------------------------------------
Function Extract(Data)
Dim strPattern,oRegExp,Matches
strPattern = "(?:\()(.*)(?:\))"
Set oRegExp = New RegExp
oRegExp.IgnoreCase = True 
oRegExp.Pattern = strPattern
set Matches = oRegExp.Execute(Data) 
If Matches.Count > 0 Then Extract = Matches(0).SubMatches(0)
End Function
'---------------------------------------------------------------

【讨论】:

    【解决方案2】:

    我认为您需要更好的数据文件;) 您可能需要考虑将文件预处理为临时文件以进行修改,以便将不符合您的模式的异常值修改为符合您的模式的位置.做起来有点费时,但当数据文件缺乏一致性时,总是很困难。

    【讨论】:

      【解决方案3】:

      编辑:检查文档后,问题是括号前有不间断的空格,而不是常规空格。所以这个正则表达式应该可以工作:""[ \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
      

      【讨论】:

      • 令人讨厌的是,它似乎不起作用。我尝试了您的文字方法并将其合并到我的方法中......这似乎与正则表达式本身存在问题:只要我只用一个工作正则表达式替换正则表达式,一切顺利。无论如何,我认为给你我现在拥有的确切的 .docm 文件可能会很有用,所以你可以看看:db.tt/6XoO1Pbn 输入文本已经在文档中。提前致谢!
      • 查看我的编辑。看起来文档中有不间断的空格。这就是搞砸我们的原因。希望它现在对你有用。
      • 这个绝对有效!我对右边界有些担心,导致括号内容中提到) 时不匹配。我想建议让正则表达式找到行中的最后一个)。但后来我找到了这个字符串:"They Called It Rock" (Lowe, Rockpile, Dave Edmunds) - 3:10 (bonus single-sided 45, credited as Rockpile, not on original LP)。我的计划是这样 :) 顺便说一句,) ) - 也不起作用,因为破折号可能会有所不同,有时在 ) 之后什么都没有。我想这无法改进,同意吗?
      • 我没有看到问题。它匹配Lowe, Rockpile, Dave Edmunds,而不是(bonus ... LP)。这就是你想要的,对吧?如果您看到不同的东西,我不知道为什么,但是,不,我会说它无法改进。
      • @BKSpureon test() 是正则表达式对象regex 上的一个方法。你传递test() 一个字符串作为参数。如果字符串与regexPattern 属性匹配,则test() 返回True。否则,False。见msdn.microsoft.com/en-us/library/y32x2hy1(v=vs.84).aspx
      【解决方案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 mentioned 的问题。例如:

      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】:

      严格来说,这不是您问题的答案,但有时,对于某些事情,这个简单、好的 ol' 字符串函数比正则表达式更容易混淆和简洁。

      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
      

      当然这比以前不那么简洁了!

      【讨论】:

      • 我也想过建议这个,但它错误地匹配“不要说话(把你的头放在我的肩膀上)”
      • +1 用于提出 OP 首选方法以外的建议。
      • 是的,我很欣赏不同的方法。我确实认为我仍然更喜欢正则表达式。我不知道它的效率(速度不是我最关心的),但我只是喜欢紧凑的符号。我对这种方法的主要担心是它似乎不是很具体。左边界最初建立为字符串的最后一个"。如果艺术家姓名包含任何引用,这将导致问题。所以我还是更喜欢用" (作为左边界。
      • 感谢您的反馈,不胜感激。解决问题的方案是最好的方案,不管具体实现如何。如您所见,有几种方法可以达到您的目标(提取子字符串)。专注于目标,而不是实现目标的特定方式。要求仅通过特定路径达到目标会限制您的选择。
      • @KeyMs92:如果艺人姓名中包含" (怎么办?我的观点是,你必须准确地定义你的问题,否则任何解决方案,无论是否正则表达式,都会有误报/误报。
      【解决方案6】:

      这是一个不错的正则表达式

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

      在 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,但我猜这就是问题所在

      如果您想进一步讨论正则表达式,我可以。我并不急于开始深入研究这个看起来很神秘的 VBscript API。

      给定新的输入,正则表达式被调整为

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

      这样它就不会错误地匹配出现在引号内的 (Put Your Head on My Shoulder)。

      【讨论】:

      • 感谢您的回复。不幸的是,使用这种模式似乎没有任何匹配。让我给你我正在测试的来源:tiny.cc/ij3ffw
      • @KeyMs92 该网页上的示例更加清晰。我更新了我的答案
      • 是的,我应该举一个更好的例子。看起来我的OP。
      • 我的正则表达式匹配第 1 组中的字符串“B. Wilson/Asher/Love”。如果您还有其他问题,请告诉我。
      • 看来问题出在正则表达式本身。使用Match 在任何情况下都不起作用。我已将我的文档文件上传到其中一个 cmets 中,您可以查看一下。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-12
      相关资源
      最近更新 更多