如何在Excel中使用正则表达式并利用Excel强大的类似于网格的设置进行数据处理?
- 单元内函数可返回匹配的模式或字符串中的替换值。
- Sub循环遍历一列数据并提取与相邻单元格的匹配项。
- 需要什么设置?
- Excel正则表达式的特殊字符是什么?
我的理解正则表达式是不理想的许多情况下(使用或不使用正则表达式?),因为Excel可以使用Left
,Mid
,Right
,Instr
类似的操作类型的命令。
如何在Excel中使用正则表达式并利用Excel强大的类似于网格的设置进行数据处理?
我的理解正则表达式是不理想的许多情况下(使用或不使用正则表达式?),因为Excel可以使用Left
,Mid
,Right
,Instr
类似的操作类型的命令。
Answers:
正则表达式用于模式匹配。
要在Excel中使用,请按照以下步骤操作:
步骤1:将VBA引用添加到“ Microsoft VBScript正则表达式5.5”
第2步:定义模式
基本定义:
-
范围。
a-z
匹配从a到z的小写字母0-5
匹配0到5之间的任何数字[]
完全匹配这些括号内的对象之一。
[a]
匹配字母a[abc]
匹配一个字母,可以是a,b或c[a-z]
匹配字母表中的任何单个小写字母。()
将不同的匹配分组以便返回。请参阅下面的示例。
{}
重复的乘数,用于重复定义的模式。
[a]{2}
匹配两个连续的小写字母a:aa
[a]{1,3}
匹配至少一个和三个小写字母a
,aa
,aaa
+
匹配至少一个或多个在其之前定义的模式。
a+
将匹配一个连续的a
,aa
,aaa
,等?
匹配零或之前定义的模式之一。
[a-z]?
匹配空字符串或任何单个小写字母。*
匹配零个或多个之前定义的模式。-例如通配符,表示可能存在或可能不存在的模式。-例如,[a-z]*
匹配空字符串或小写字母字符串。
.
匹配换行符以外的任何字符 \n
a.
匹配两个字符串,以a开头,以除以下以外的任何结尾\n
|
OR运算符
a|b
表示a
或b
可以匹配。red|white|orange
正好匹配一种颜色。^
非运算符
[^0-9]
字符不能包含数字[^aA]
字符不能小写a
或大写A
\
转义后面的特殊字符(覆盖行为之上)
\.
,\\
,\(
,\?
,\$
,\^
锚定模式:
^
匹配必须在字符串开头
^a
第一个字符必须为小写字母a
^[0-9]
第一个字符必须是数字。$
匹配必须发生在字符串的末尾
a$
最后一个字符必须为小写字母a
优先级表:
Order Name Representation
1 Parentheses ( )
2 Multipliers ? + * {m,n} {m, n}?
3 Sequence & Anchors abc ^ $
4 Alternation |
预定义的字符缩写:
abr same as meaning
\d [0-9] Any single digit
\D [^0-9] Any single character that's not a digit
\w [a-zA-Z0-9_] Any word character
\W [^a-zA-Z0-9_] Any non-word character
\s [ \r\t\n\f] Any space character
\S [^ \r\t\n\f] Any non-space character
\n [\n] New line
示例1:作为宏运行
下面的示例宏查看单元格中的值,A1
以查看前1个或2个字符是否为数字。如果是这样,它们将被删除并显示字符串的其余部分。如果没有,则会出现一个框,告诉您找不到匹配项。单元格A1
值12abc
will将返回abc
,值of 1abc
将返回abc
,值of abc123
将返回“不匹配”,因为数字不在字符串的开头。
Private Sub simpleRegex()
Dim strPattern As String: strPattern = "^[0-9]{1,2}"
Dim strReplace As String: strReplace = ""
Dim regEx As New RegExp
Dim strInput As String
Dim Myrange As Range
Set Myrange = ActiveSheet.Range("A1")
If strPattern <> "" Then
strInput = Myrange.Value
With regEx
.Global = True
.MultiLine = True
.IgnoreCase = False
.Pattern = strPattern
End With
If regEx.Test(strInput) Then
MsgBox (regEx.Replace(strInput, strReplace))
Else
MsgBox ("Not matched")
End If
End If
End Sub
示例2:作为单元内函数运行
该示例与示例1相同,但设置为作为单元内功能运行。要使用,请将代码更改为此:
Function simpleCellRegex(Myrange As Range) As String
Dim regEx As New RegExp
Dim strPattern As String
Dim strInput As String
Dim strReplace As String
Dim strOutput As String
strPattern = "^[0-9]{1,3}"
If strPattern <> "" Then
strInput = Myrange.Value
strReplace = ""
With regEx
.Global = True
.MultiLine = True
.IgnoreCase = False
.Pattern = strPattern
End With
If regEx.test(strInput) Then
simpleCellRegex = regEx.Replace(strInput, strReplace)
Else
simpleCellRegex = "Not matched"
End If
End If
End Function
将您的字符串(“ 12abc”)放在cell中A1
。=simpleCellRegex(A1)
在单元格中输入此公式,B1
结果将为“ abc”。
示例3:循环范围
此示例与示例1相同,但循环通过一系列单元。
Private Sub simpleRegex()
Dim strPattern As String: strPattern = "^[0-9]{1,2}"
Dim strReplace As String: strReplace = ""
Dim regEx As New RegExp
Dim strInput As String
Dim Myrange As Range
Set Myrange = ActiveSheet.Range("A1:A5")
For Each cell In Myrange
If strPattern <> "" Then
strInput = cell.Value
With regEx
.Global = True
.MultiLine = True
.IgnoreCase = False
.Pattern = strPattern
End With
If regEx.Test(strInput) Then
MsgBox (regEx.Replace(strInput, strReplace))
Else
MsgBox ("Not matched")
End If
End If
Next
End Sub
示例4:拆分不同的模式
本示例循环遍历一个范围(A1
,A2
&A3
),并查找一个字符串,该字符串以三位数字开头,后跟一个字母字符,然后是4位数字。输出使用来将模式匹配拆分为相邻的单元格()
。 $1
表示在的第一组内匹配的第一个模式()
。
Private Sub splitUpRegexPattern()
Dim regEx As New RegExp
Dim strPattern As String
Dim strInput As String
Dim Myrange As Range
Set Myrange = ActiveSheet.Range("A1:A3")
For Each C In Myrange
strPattern = "(^[0-9]{3})([a-zA-Z])([0-9]{4})"
If strPattern <> "" Then
strInput = C.Value
With regEx
.Global = True
.MultiLine = True
.IgnoreCase = False
.Pattern = strPattern
End With
If regEx.test(strInput) Then
C.Offset(0, 1) = regEx.Replace(strInput, "$1")
C.Offset(0, 2) = regEx.Replace(strInput, "$2")
C.Offset(0, 3) = regEx.Replace(strInput, "$3")
Else
C.Offset(0, 1) = "(Not matched)"
End If
End If
Next
End Sub
结果:
附加图案示例
String Regex Pattern Explanation
a1aaa [a-zA-Z][0-9][a-zA-Z]{3} Single alpha, single digit, three alpha characters
a1aaa [a-zA-Z]?[0-9][a-zA-Z]{3} May or may not have preceding alpha character
a1aaa [a-zA-Z][0-9][a-zA-Z]{0,3} Single alpha, single digit, 0 to 3 alpha characters
a1aaa [a-zA-Z][0-9][a-zA-Z]* Single alpha, single digit, followed by any number of alpha characters
</i8> \<\/[a-zA-Z][0-9]\> Exact non-word character except any single alpha followed by any single digit
Set regEx = Nothing
。当该Sub被频繁执行时,您将获得“内存不足”异常。
Set regEx = CreateObject("VBScript.RegExp")
ThisWorkbook
。尝试将代码移到单独的Module
。
要直接在Excel公式中使用正则表达式,以下UDF(用户定义函数)可能会有所帮助。它或多或少直接将正则表达式功能公开为excel函数。
它需要2-3个参数。
$0
,$1
,$2
,等等。$0
是整个匹配项,$1
并且up对应于正则表达式中的各个匹配项组。默认为$0
。提取电子邮件地址:
=regex("Peter Gordon: some@email.com, 47", "\w+@\w+\.\w+")
=regex("Peter Gordon: some@email.com, 47", "\w+@\w+\.\w+", "$0")
结果是: some@email.com
提取几个子字符串:
=regex("Peter Gordon: some@email.com, 47", "^(.+): (.+), (\d+)$", "E-Mail: $2, Name: $1")
结果是: E-Mail: some@email.com, Name: Peter Gordon
要将单个单元格中的组合字符串分解成多个单元格中的组件,请执行以下操作:
=regex("Peter Gordon: some@email.com, 47", "^(.+): (.+), (\d+)$", "$" & 1)
=regex("Peter Gordon: some@email.com, 47", "^(.+): (.+), (\d+)$", "$" & 2)
结果:Peter Gordon
some@email.com
...
要使用此UDF,请执行以下操作(大致基于此Microsoft页面。它们在此处有一些不错的附加信息!):
ALT+F11
以打开Microsoft Visual Basic for Applications编辑器。单击插入模块。如果你给你的模块不同的名称确保模块并不会具有相同的名称作为下面的UDF(如命名的模块Regex
和功能regex
导致#NAME!错误)。
在中间的大文本窗口中,插入以下内容:
Function regex(strInput As String, matchPattern As String, Optional ByVal outputPattern As String = "$0") As Variant
Dim inputRegexObj As New VBScript_RegExp_55.RegExp, outputRegexObj As New VBScript_RegExp_55.RegExp, outReplaceRegexObj As New VBScript_RegExp_55.RegExp
Dim inputMatches As Object, replaceMatches As Object, replaceMatch As Object
Dim replaceNumber As Integer
With inputRegexObj
.Global = True
.MultiLine = True
.IgnoreCase = False
.Pattern = matchPattern
End With
With outputRegexObj
.Global = True
.MultiLine = True
.IgnoreCase = False
.Pattern = "\$(\d+)"
End With
With outReplaceRegexObj
.Global = True
.MultiLine = True
.IgnoreCase = False
End With
Set inputMatches = inputRegexObj.Execute(strInput)
If inputMatches.Count = 0 Then
regex = False
Else
Set replaceMatches = outputRegexObj.Execute(outputPattern)
For Each replaceMatch In replaceMatches
replaceNumber = replaceMatch.SubMatches(0)
outReplaceRegexObj.Pattern = "\$" & replaceNumber
If replaceNumber = 0 Then
outputPattern = outReplaceRegexObj.Replace(outputPattern, inputMatches(0).Value)
Else
If replaceNumber > inputMatches(0).SubMatches.Count Then
'regex = "A to high $ tag found. Largest allowed is $" & inputMatches(0).SubMatches.Count & "."
regex = CVErr(xlErrValue)
Exit Function
Else
outputPattern = outReplaceRegexObj.Replace(outputPattern, inputMatches(0).SubMatches(replaceNumber - 1))
End If
End If
Next
regex = outputPattern
End If
End Function
保存并关闭“ Microsoft Visual Basic应用程序编辑器”窗口。
Function foo() As Variant \n foo="Hello World" \n End Function
UDF以查看是否可行。如果是,请继续进行上述操作,如果基本内容没有损坏(禁用宏?)。
添加以下代码:
Function RegxFunc(strInput As String, regexPattern As String) As String
Dim regEx As New RegExp
With regEx
.Global = True
.MultiLine = True
.IgnoreCase = False
.pattern = regexPattern
End With
If regEx.Test(strInput) Then
Set matches = regEx.Execute(strInput)
RegxFunc = matches(0).Value
Else
RegxFunc = "not matched"
End If
End Function
将正则表达式模式放在其中一个单元格中,并在其上使用绝对引用。
函数将与其创建的工作簿联系在一起。
如果需要在不同的工作簿中使用它,请将函数存储在Personal.XLSB中
这是我的尝试:
Function RegParse(ByVal pattern As String, ByVal html As String)
Dim regex As RegExp
Set regex = New RegExp
With regex
.IgnoreCase = True 'ignoring cases while regex engine performs the search.
.pattern = pattern 'declaring regex pattern.
.Global = False 'restricting regex to find only first match.
If .Test(html) Then 'Testing if the pattern matches or not
mStr = .Execute(html)(0) '.Execute(html)(0) will provide the String which matches with Regex
RegParse = .Replace(mStr, "$1") '.Replace function will replace the String with whatever is in the first set of braces - $1.
Else
RegParse = "#N/A"
End If
End With
End Function
我需要将其用作单元函数(如SUM
或VLOOKUP
),发现很容易:
在工作簿中或在其自己的模块中创建以下函数:
Function REGPLACE(myRange As Range, matchPattern As String, outputPattern As String) As Variant
Dim regex As New VBScript_RegExp_55.RegExp
Dim strInput As String
strInput = myRange.Value
With regex
.Global = True
.MultiLine = True
.IgnoreCase = False
.Pattern = matchPattern
End With
REGPLACE = regex.Replace(strInput, outputPattern)
End Function
然后,您可以在单元格中使用=REGPLACE(B1, "(\w) (\d+)", "$1$2")
(例如:“ A 243”至“ A243”)
这不是直接的答案,但可以为您的考虑提供更有效的选择。就是说Google表格有几个内置的Regex函数,这些函数非常方便,可以帮助绕开Excel中的某些技术步骤。显然,在PC上使用Excel有一些优势,但是对于绝大多数用户而言,Google表格将提供相同的体验,并且在可移植性和文档共享方面可能会带来一些优势。
他们提供
REGEXEXTRACT:根据正则表达式提取匹配的子字符串。
REGEXREPLACE:使用正则表达式将文本字符串的一部分替换为其他文本字符串。
替换:用字符串中的新文本替换现有文本。
替换:用其他文本字符串替换文本字符串的一部分。
您可以像这样直接将它们键入到单元格中,并产生您想要的任何内容
=REGEXMATCH(A2, "[0-9]+")
它们还可以与其他功能(例如IF语句)结合使用,如下所示:
=IF(REGEXMATCH(E8,"MiB"),REGEXEXTRACT(E8,"\d*\.\d*|\d*")/1000,IF(REGEXMATCH(E8,"GiB"),REGEXEXTRACT(E8,"\d*\.\d*|\d*"),"")
希望这为那些被Excel的VBS组件困扰的用户提供了一个简单的解决方法。
这是一个 regex_subst()
功能。例子:
=regex_subst("watermellon", "[aeiou]", "")
---> wtrmlln
=regex_subst("watermellon", "[^aeiou]", "")
---> aeeo
这是简化的代码(无论如何对我来说更简单)。我无法弄清楚如何使用上述方法构建合适的输出模式,如我的示例所示:
Function regex_subst( _
strInput As String _
, matchPattern As String _
, Optional ByVal replacePattern As String = "" _
) As Variant
Dim inputRegexObj As New VBScript_RegExp_55.RegExp
With inputRegexObj
.Global = True
.MultiLine = True
.IgnoreCase = False
.Pattern = matchPattern
End With
regex_subst = inputRegexObj.Replace(strInput, replacePattern)
End Function
我不需要启用参考库,因为我需要脚本具有可移植性。该Dim foo As New VBScript_RegExp_55.RegExp
行导致了User Defined Type Not Defined
错误,但是我找到了适合我的解决方案。
您需要做的是将一个示例字符串放入单元格A1
,然后测试您的strPattern
。一旦起作用,则rng
根据需要进行调整。
Public Sub RegExSearch()
'/programming/22542834/how-to-use-regular-expressions-regex-in-microsoft-excel-both-in-cell-and-loops
'https://wellsr.com/vba/2018/excel/vba-regex-regular-expressions-guide/
'https://www.vitoshacademy.com/vba-regex-in-excel/
Dim regexp As Object
'Dim regex As New VBScript_RegExp_55.regexp 'Caused "User Defined Type Not Defined" Error
Dim rng As Range, rcell As Range
Dim strInput As String, strPattern As String
Set regexp = CreateObject("vbscript.regexp")
Set rng = ActiveSheet.Range("A1:A1")
strPattern = "([a-z]{2})([0-9]{8})"
'Search for 2 Letters then 8 Digits Eg: XY12345678 = Matched
With regexp
.Global = False
.MultiLine = False
.ignoreCase = True
.Pattern = strPattern
End With
For Each rcell In rng.Cells
If strPattern <> "" Then
strInput = rcell.Value
If regexp.test(strInput) Then
MsgBox rcell & " Matched in Cell " & rcell.Address
Else
MsgBox "No Matches!"
End If
End If
Next
End Sub
VBScript_RegExp_55
库几乎无处不在,因此携带不在特定目标计算机上的风险非常低。而且无论如何,从“早期绑定”切换到“后期绑定”并不能解决可移植性问题(代码仍然会出错,仅在运行时而不是在编译时)
为了增加有价值的内容,我想提醒一下为什么有时VBA中的RegEx不理想。并非所有表达式都受支持,而是可能引发Error 5017
并可能使作者猜测(我是我自己的受害者)。
虽然我们可以找到一些资源什么是支持的,这将是有益的知道哪些元字符等的不支持。在这里可以找到更深入的解释。在此来源中提及:
“尽管” VBScript的正则表达式... 5.5版实现了VBScript早期版本中缺少的许多正则表达式基本功能。... JavaScript和VBScript实现Perl样式的正则表达式。但是,它们缺少Perl和其他现代正则表达式形式中可用的许多高级功能:”
因此,不支持的是:
\A
,或者使用^
插入符号匹配字符串中第一个字符之前的位置\Z
,或者使用$
美元符号来匹配字符串中最后一个字符之后的位置(?<=a)b
(同时阳性预读的支持)(?<!a)b
(同时排除模式的支持)\{uFFFF}
/i
区分大小写)或/g
(全局)等。可通过RegExp
对象属性> RegExp.Global = True
和(RegExp.IgnoreCase = True
如果可用)进行设置。'
在脚本中添加带有常规注释的内容我已经在VBA中使用正则表达式多次碰壁。通常,LookBehind
但有时我什至会忘记修饰符。我本人还没有经历过所有上述背景,但是我想我会尝试广泛参考一些更深入的信息。随时评论/更正/添加。向regular-expressions.info大喊大叫,以获取大量信息。
PS:您已经提到了常规的VBA方法和函数,并且我可以确认它们(至少对我来说)在RegEx失败时以它们自己的方式有所帮助。