【问题标题】:Regular expression for an Excel cell with R1C1 notation具有 R1C1 表示法的 Excel 单元格的正则表达式
【发布时间】:2017-04-27 23:18:40
【问题描述】:

我需要一些代码来测试一个单元格是否包含一个引用另一个单元格的公式。

我找到了答案Find all used references in Excel formula,但解决方案也错误地匹配了引用表格列的公式:

=SearchValInCol2(Tabella1[articolo];[@articolo];Tabella1[b])

然后,我使用 Like 运算符编写了以下 VBA 代码,但使用正则表达式的解决方案肯定会更可靠(我认为以下代码在许多情况下都不起作用)。

Private Function TestIfCellContainsAFormula(cellToTest As Variant) As Boolean

    Dim result As Object
    Dim r As Range
    Dim testExpression As String
    Dim objRegEx As Object

    Set r = cellToTest  ' INPUT THE CELL HERE , e.g.    RANGE("A1")
    Set objRegEx = CreateObject("VBScript.RegExp")
    objRegEx.IgnoreCase = True
    objRegEx.Global = True
    objRegEx.Pattern = """.*?"""  ' remove expressions
    testExpression = CStr(r.FormulaR1C1)

    ' search for pattern "=R[-3]C+4"
    If testExpression Like "*R[[]*[]]*C*" Then
        TestIfCellContainsAFormula2 = True
        Exit Function
    End If

    ' search for pattern "=RC[2]"
    If testExpression Like "*R*C[[]*[]]*" Then
    'If InStr(1, testExpression, "C[", vbTextCompare) <> 0 Then
        TestIfCellContainsAFormula2 = True
        Exit Function
    End If

    TestIfCellContainsAFormula2 = False

End Function

【问题讨论】:

标签: regex vba excel


【解决方案1】:

选项 1

要匹配 R1C1 样式引用,您可以使用 this regex:

R(\[-?\d+\])C(\[-?\d+\])|R(\[-?\d+\])C|RC(\[-?\d+\])

查看railroad 图表以获得直观的解释:

核心是“偏移量”,它是-?\d+,它是可选的-,后跟一个数字或更多。这个序列放在括号 ([]) 中,得到\[-?\d+\]。然后正则表达式允许以下组合:

  • R[offset]C[offset]
  • R[offset]C 或 (|)
  • RC[offset] 或 (|)

选项 2

上面的正则表达式不会匹配 RCRC。它将匹配 R[0]C[0]R[0]CRC[0]R[0]C[0],它们是等价的。要消除这些匹配项,您可以使用 this regex:

R(\[-?[1-9][0-9]*\])C(\[-?[1-9][0-9]*\])|R(\[-?[1-9][0-9]*\])C|RC(\[-?[1-9][0-9]*\])

这是:

但似乎在我的 Excel (v2013) 中输入 R[0]C[0]R[0]C[0] 会将它们变成 RCRC 无论如何 - 所以你可以避免额外的复杂性,如果这是不用担心。

选项 3

如果您想允许RCRC,您可以使用更简单的正则表达式:

R(\[-?\d+\])?C(\[-?\d+\])?

VBA 测试代码

这使用选项 1。

Option Explicit

Sub Test()

    Dim varTests As Variant
    Dim varTest As Variant
    Dim varMatches As Variant
    Dim varMatch As Variant

    varTests = Array("RC", _
        "R[1]C", _
        "RC[1]", _
        "R[1]C[1]", _
        "R[-1]C", _
        "RC[-1]", _
        "R[-1]C[-1]", _
        "=SUM(A1:B2)", _
        "RC[1]+R[-1]C+R[2]C[-99]", _
        "R[-1]C-R[1]C[-44]-RC[999]+R[0]C[0]", _
        "SearchValInCol2(Tabella1[articolo];[@articolo];Tabella1[b])")

    For Each varTest In varTests
        varMatches = FormulaContainsR1C1Reference(CStr(varTest))
        Debug.Print "Input: " & CStr(varTest)
        Debug.Print VBA.String(Len(CStr(varTest)) + 7, "-")

        If IsEmpty(varMatches) Then
            Debug.Print "No matches"
        Else
            Debug.Print UBound(varMatches) & " matches"
            For Each varMatch In varMatches
                Debug.Print varMatch
            Next varMatch
        End If

        Debug.Print vbCrLf
    Next varTest

End Sub

Function FormulaContainsR1C1Reference(ByVal strFormula As String) As Variant

    Dim objRegex As Object
    Dim strPattern As String
    Dim objMatches As Object
    Dim varMatches As Variant
    Dim lngCounter As Long

    Set objRegex = CreateObject("VBScript.RegExp")
    With objRegex
        ' setup regex
        .Global = True
        .IgnoreCase = False
        .Pattern = "R(\[-?\d+\])C(\[-?\d+\])|R(\[-?\d+\])C|RC(\[-?\d+\])"

        ' get matches
        Set objMatches = .Execute(strFormula)

        ' iterate matches
        If objMatches.Count > 0 Then
            ReDim varMatches(1 To objMatches.Count)
            For lngCounter = 1 To objMatches.Count
                varMatches(lngCounter) = objMatches.Item(lngCounter - 1)
            Next lngCounter
        Else
            varMatches = Empty
        End If

    End With

    FormulaContainsR1C1Reference = varMatches

End Function

A1 样式参考

我为 A1 样式参考发布了一个正则表达式 here

^(?:[A-Z]|[A-Z][A-Z]|[A-X][A-F][A-D])(?:[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9][0-9]|10[0-3][0-9][0-9][0-9][0-9]|104[0-7][0-9][0-9][0-9]|1048[0-4][0-9][0-9]|10485[0-6][0-9]|104857[0-6])$

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多