在正斜杠上分割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|$)
它可以很容易地分成两个结构:
- 首先,子模式
((?:(?!//|\band\b).)*)
是一个匹配每个标记的组 ,反向引用我们想要为每个匹配返回的文本。 在vba中 ,组以.SubMatches()
返回。 让我们把它压制下来:- 内部expression式
(?!//|\band\b).
首先检查以确保它没有跟随一个拆分string (“/”或“and
”)。 如果不是,则正则expression式引擎匹配一个字符(注意最后一个点)。 就是这样,它匹配了我们捕获的令牌的一部分所允许的一个字符。 - 现在,它被包含在
(?:(?!//|\band\b).)*
为每个可以匹配的字符重复一遍,我们得到了令牌中的所有字符。 这个构造是最接近它可以得到一个while循环 。
虽然它不是一个拆分string,得到下一个字符。
- 如果你仔细想一下,那就是构造
.*
我们都知道,每个angular色都有一个额外的条件。
- 内部expression式
- 第二个子模式
(?://|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"
其余的模式是简单的细节:
-
(?!$)
是为了避免匹配行尾的空string。 - 所有
\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-