在正斜杠上分割string和/或用RegExp特定字词

我试图通过双正斜线和/或特定的string(如“和”)来分割文本。

Example A: text1 a/s // text2 a/b text1 a/s and text2 a/b Example B: text1. // text2,// text3- text1. and text2, and text3- 
  • 示例A返回两个匹配:text1 a / s text2 a / b
  • 示例B返回三个匹配项:text1。 text2,text3-

我得到了非常有用的技巧,如何通过单个正斜杠进行分割:单个正向拆分string与RegExp ,但试图find一个解决scheme,排除两个正斜杠或string,被certificate是太具有挑战性。

附加点,如果可以结合两个例子的解决scheme组合:

 Example C: text1 a/s // text2, and text3- 

我将不胜感激只有RegExp解决scheme与VBA兼容。

正如你所说,你已经有了一个工作解决scheme,用于分割string中的不同分割字符, 使用RegExp在单个正斜杠上 。 该代码实际上并不分割string,但它匹配除“ / ”之外的所有内容。 然后它返回collection中每个单独匹配的结果(是的,它最终分裂)。

你需要做的是在str匹配每个字符,除非接下来的字符是//或者。 我们可以用这个向前看 。

只需使用以下代码更改代码中的模式:

 .Pattern = "(?!$)((?:(?!//|\band\b).)*)(?://|and|$)" 

或者,如果您要修剪每个标记的空格,请使用以下正则expression式:

 .Pattern = "(?!$)((?:(?!\s*//|\s*\band\b).)*)\s*(?://|and|$)\s*" 

虽然这也将匹配//and ,它使用( group )来捕获实际的令牌。 因此,必须使用.SubMatches(0) (第一组反向引用的内容.SubMatches(0)将标记添加到集合中。

在你的代码中,而不是添加coll.Add r_item.Value ,使用:

 coll.Add r_item.SubMatches(0) 

注意:如果你的string有换行符,不要忘记用.Multiline = True设置rExp对象。


VBA代码:

 Sub GetMatches(ByRef str As String, ByRef coll As Collection) Dim rExp As Object, rMatch As Object Set rExp = CreateObject("vbscript.regexp") With rExp .Global = True .MultiLine = True .Pattern = "(?!$)((?:(?!\s*//|\s*\band\b).)*)\s*(?://|and|$)\s*" End With Set rMatch = rExp.Execute(str) If rMatch.Count > 0 Then For Each r_item In rMatch coll.Add r_item.subMatches(0) Next r_item End If End Sub 

这就是你可以用你的例子调用它的方法:

 Dim text As String text = "t/xt1.//text2,and landslide/ andy // text3- and text4" 'vars to get result of RegExp Dim matches As New Collection, token Set matches = New Collection 'Exec the RegExp --> Populate matches GetMatches text, matches 'Print each token in debug window For Each token In matches Debug.Print "'" & token & "'" Next token Debug.Print "=======" 

每个令牌都被打印在即时窗口中。

  • 此代码是@stribizhev最初发布的代码的修改版本

立即窗口输出:

 't/xt1.' 'text2,' 'landslide/ andy' 'text3-' 'text4' ======= 

更深入的解释

你可能想知道这个模式是如何工作的 我会尽力解释一下详细的描述。 为了做到这一点,我们只使用以下正则expression式中的重要部分(其余部分并不重要):

 ((?:(?!//|\band\b).)*)(?://|and|$) 

它可以很容易地分成两个结构:

  1. 首先,子模式((?:(?!//|\band\b).)*)是一个匹配每个标记的组 ,反向引用我们想要为每个匹配返回的文本。 在vba中 ,组以.SubMatches()返回。 让我们把它压制下来:
    • 内部expression式(?!//|\band\b). 首先检查以确保它没有跟随一个拆分string (“/”或“ and ”)。 如果不是,则正则expression式引擎匹配一个字符(注意最后一个点)。 就是这样,它匹配了我们捕获的令牌的一部分所允许的一个字符。
    • 现在,它被包含在(?:(?!//|\band\b).)*为每个可以匹配的字符重复一遍,我们得到了令牌中的所有字符。 这个构造是最接近它可以得到一个while循环 。

      虽然它不是一个拆分string,得到下一个字符。

    • 如果你仔细想一下,那就是构造.*我们都知道,每个angular色都有一个额外的条件。
  2. 第二个子模式(?://|and|$)更简单,只需匹配一个拆分string (“ // ”,“ and ”或行尾)。 它位于非捕获组内 ,意味着它将被匹配,但不会存储其值的副本。

例如:

 text1 a/s and text2 a/b//last ^ ^| | [1]: 1st subpattern, captured in Matches(0).SubMatches(0) |--------|^-^ | 1 2| [2]: Split string, not captured but included in match |-----------| 3 [3]: The whole match, returned by Matches(0) For the second match, Matches(1).Value = " text2 a/b//" Matches(1).Submatches(0) = " text2 a/b" 

其余的模式是简单的细节:

  1. (?!$)是为了避免匹配行尾的空string。
  2. 所有\s*都在那里修剪令牌(以避免在开始或结束令牌时捕获空格)。

最简单的方法是:

 Text = "text1 a/s // text2, and text3-" text = Replace(text, " // ", vbNewLine) text = Replace(text, " and ", vbNewLine) arr = Split(text, vbNewLine) For Each field In arr WScript.Echo Trim(field) 'Using Trim you can remove the spaces around Next 

你会得到:

 text1 a/s text2, text3-