如何在单元格和循环中使用Microsoft Excel中的正则表达式(Regex)


592

如何在Excel中使用正则表达式并利用Excel强大的类似于网格的设置进行数据处理?

  • 单元内函数可返回匹配的模式或字符串中的替换值。
  • Sub循环遍历一列数据并提取与相邻单元格的匹配项。
  • 需要什么设置?
  • Excel正则表达式的特殊字符是什么?

我的理解正则表达式是不理想的许多情况下(使用或不使用正则表达式?),因为Excel可以使用LeftMidRightInstr类似的操作类型的命令。


11
强烈

1
试试这个免费的插件:seotoolsforexcel.com/regexpfind
Niels Bosma

1
我们不要忘记Like operator,它提供了一种轻巧的正则表达式样式功能。即使包装在子过程或函数过程中,它通常比regex快得多。
Egalth

Answers:


955

正则表达式用于模式匹配。

要在Excel中使用,请按照以下步骤操作:

步骤1:将VBA引用添加到“ Microsoft VBScript正则表达式5.5”

  • 选择“开发人员”标签(我没有此标签,我该怎么办?
  • 从“代码”功能区部分选择“ Visual Basic”图标
  • 在“ Microsoft Visual Basic应用程序”窗口中,从顶部菜单中选择“工具”。
  • 选择“参考”
  • 选中要包含在您的工作簿中的“ 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}匹配至少一个和三个小写字母aaaaaa

+ 匹配至少一个或多个在其之前定义的模式。

  • 例如,a+将匹配一个连续的aaaaaa,等

? 匹配零或之前定义的模式之一。

  • 例如,模式可能会或可能不会出现,但只能匹配一次。
  • 例如,[a-z]?匹配空字符串或任何单个小写字母。

* 匹配零个或多个之前定义的模式。-例如通配符,表示可能存在或可能不存在的模式。-例如,[a-z]*匹配空字符串或小写字母字符串。

. 匹配换行符以外的任何字符 \n

  • 例如,a.匹配两个字符串,以a开头,以除以下以外的任何结尾\n

| OR运算符

  • 例如,a|b表示ab可以匹配。
  • 例如,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个字符是否为数字。如果是这样,它们将被删除并显示字符串的其余部分。如果没有,则会出现一个框,告诉您找不到匹配项。单元格A112abcwill将返回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:拆分不同的模式

本示例循环遍历一个范围(A1A2A3),并查找一个字符串,该字符串以三位数字开头,后跟一个字母字符,然后是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

22
你不应该忘记Set regEx = Nothing。当该Sub被频繁执行时,您将获得“内存不足”异常。
基里尔2015年

1
我适应例如4 子匹配治疗更复杂的正则表达式,我基本上不用更换分裂时,如果有人有兴趣:stackoverflow.com/questions/30218413/...
Armfoot

11
后期装订线:Set regEx = CreateObject("VBScript.RegExp")
ZygD 2015年

2
好的,我很确定这是因为代码在中ThisWorkbook。尝试将代码移到单独的Module
波特兰赛跑者

3
尽管其他文件显示了一个文件,但“ excel”文件中的“项目资源管理器”(?)中的@PortlandRunner缺少“模块”子文件夹。右键单击该文件,然后选择“插入模块”,然后双击“模块1”并粘贴代码。已保存。回到工作簿并再次键入功能-它起作用了。为了像我这样缺乏经验的人,答案可能值得注意。谢谢您的帮助。
youcantryreachingme

205

要直接在Excel公式中使用正则表达式,以下UDF(用户定义函数)可能会有所帮助。它或多或少直接将正则表达式功能公开为excel函数。

怎么运行的

它需要2-3个参数。

  1. 使用正则表达式的文本。
  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页面。它们在此处有一些不错的附加信息!):

  1. 在Excel中启用宏的文件('.xlsm')中,按一下ALT+F11以打开Microsoft Visual Basic for Applications编辑器。
  2. 将VBA引用添加到正则表达式库(从Portland Runners ++ answer中无耻地复制):
    1. 点击工具 -> 参考(请原谅德语截图) 工具->参考
    2. 在列表中找到Microsoft VBScript正则表达式5.5,然后选中它旁边的复选框。
    3. 单击确定
  3. 单击插入模块。如果你给你的模块不同的名称确保模块并不会具有相同的名称作为下面的UDF(如命名的模块Regex和功能regex导致#NAME!错误)。

    图标行中的第二个图标->模块

  4. 在中间的大文本窗口中,插入以下内容:

    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
  5. 保存并关闭“ Microsoft Visual Basic应用程序编辑器”窗口。


6
这个答案与此处创建外接程序的步骤结合在一起非常有用。谢谢。确保您不给模块和功能使用相同的名称!
克里斯·亨特

2
只是重申克里斯·亨特(Chris Hunt)的上述评论。也不要将您的模块称为“ Regex”。我以为我要疯了一段时间,因为功能是行不通的,由于一个#NAME错误
克里斯-

好吧,我在尝试一切(包括更改模块/名称)时仍然发疯
Enissay,2016年

@Enissay:尝试创建最小的Function foo() As Variant \n foo="Hello World" \n End FunctionUDF以查看是否可行。如果是,请继续进行上述操作,如果基本内容没有损坏(禁用宏?)。
PatrickBöker16年


64

急于扩展patszim答案

  1. 打开Excel工作簿。
  2. Alt+ F11打开VBA /宏窗口。
  3. 正则表达式来下的添加引用工具,然后引用
    ![Excel VBA表单添加参考
  4. 并选择Microsoft VBScript正则表达式5.5
    ![Excel VBA添加正则表达式参考
  5. 插入一个新模块(代码需要驻留在模块中,否则它将不起作用)。
    ![Excel VBA插入代码模块
  6. 在新插入的模块中,
    ![Excel VBA将代码插入模块
  7. 添加以下代码:

    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
  8. 将正则表达式模式放在其中一个单元格中,并在其上使用绝对引用![Excel regex函数的单元内用法 函数将与其创建的工作簿联系在一起。
    如果需要在不同的工作簿中使用它,请将函数存储在Personal.XLSB中


1
感谢您提到它,它必须存在于Personal.xlsb中,才能在您处理的所有Excel文档中使用。大多数(?)其他答案不清楚。Personal.XLSB将进入文件夹(可能需要创建文件夹)C:\ Users \用户名\ AppData \ Local \ Microsoft \ Excel \ XLStart文件夹
Mark Stewart

26

这是我的尝试:

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

9

我需要将其用作单元函数(如SUMVLOOKUP),发现很容易:

  1. 确保您在启用宏的Excel文件中(另存为xlsm)。
  2. 打开开发人员工具Alt+F11
  3. 在其他答案中添加Microsoft VBScript正则表达式5.5
  4. 在工作簿中或在其自己的模块中创建以下函数:

    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
  5. 然后,您可以在单元格中使用=REGPLACE(B1, "(\w) (\d+)", "$1$2")(例如:“ A 243”至“ A243”)


outputPattern的这种命名使我失望。这是重置价值。
雷神(Thor)

1
是。我想我把它命名为图案,从而很显然它不只是字符串替换,你可以使用正则表达式匹配团体,如$ 1 $ 2等等
DeezCashews

7

这不是直接的答案,但可以为您的考虑提供更有效的选择。就是说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组件困扰的用户提供了一个简单的解决方法。


感谢您分享Alex。这对于寻找Google版本的用户很有用。您可能会考虑撰写和回答另一个针对Google Sheets Regex的问题,因为它具有自己的术语,对其他人非常有用。无论如何,您有我的支持!
波特兰赛跑者

4

这是一个 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

1

我不需要启用参考库,因为我需要脚本具有可移植性。该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库几乎无处不在,因此携带不在特定目标计算机上的风险非常低。而且无论如何,从“早期绑定”切换到“后期绑定”并不能解决可移植性问题(代码仍然会出错,仅在运行时而不是在编译时)
chris neilsen

1
不,那根本不是真的,该脚本可以与其他用户共享,而无需他们启用任何可移植的功能。感谢您
FreeSoftwareServers

1
可以,但是RegEx代码将不可。如果RegEx内容是更大的图书馆工作手册的一部分,我
想让

1

为了增加有价值的内容,我想提醒一下为什么有时VBA中的RegEx不理想。并非所有表达式都受支持,而是可能引发Error 5017并可能使作者猜测(我是我自己的受害者)。

虽然我们可以找到一些资源什么支持的,这将是有益的知道哪些元字符等的支持。在这里可以找到更深入的解释。在此来源中提及:

“尽管” VBScript的正则表达式... 5.5版实现了VBScript早期版本中缺少的许多正则表达式基本功能。... JavaScript和VBScript实现Perl样式的正则表达式。但是,它们缺少Perl和其他现代正则表达式形式中可用的许多高级功能:”


因此,支持的是:

  • 字符串ancor的开始\A,或者使用^插入符号匹配字符串中第一个字符之前的位置
  • 字符串ancor的结尾\Z,或者使用$美元符号来匹配字符串中最后一个字符之后的位置
  • 正回顾后,如:(?<=a)b(同时阳性预读支持)
  • 负回顾后,如:(?<!a)b(同时排除模式支持)
  • 原子分组
  • 所有格量词
  • Unicode,例如: \{uFFFF}
  • 命名为捕获组。或者使用编号捕获组
  • 内联修饰符,例如:(/i区分大小写)或/g(全局)等。可通过RegExp对象属性> RegExp.Global = True和(RegExp.IgnoreCase = True如果可用)进行设置。
  • 有条件的
  • 正则表达式注释'在脚本中添加带有常规注释的内容

我已经在VBA中使用正则表达式多次碰壁。通常,LookBehind但有时我什至会忘记修饰符。我本人还没有经历过所有上述背景,但是我想我会尝试广泛参考一些更深入的信息。随时评论/更正/添加。向regular-expressions.info大喊大叫,以获取大量信息。

PS:您已经提到了常规的VBA方法和函数,并且我可以确认它们(至少对我来说)在RegEx失败时以它们自己的方式有所帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.