具有R1C1表示法的Excel单元格的正则表达式

时间:2017-04-27 01:02:54

标签: regex excel vba excel-vba

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

我找到了答案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

1 个答案:

答案 0 :(得分:0)

选项1

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

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

有关直观说明,请参阅railroad图表:

enter image description here

核心是&#39;偏移&#39; -?\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]*\])

这是:enter image description here

但似乎在我的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])$