9

絶対参照、相対参照、および外部参照を含む、Excel 数式の任意の参照に一致する正規表現パターンを作成しようとしています。ワークシートとワークブック名​​を含む参照全体を返す必要があります。

Excel の A1 表記法に関する完全なドキュメントを見つけることはできませんでしたが、多くのテストを行った結果、次のことがわかりました。

  • 式の前に等号「=」を付ける
  • 数式内の文字列は二重引用符で囲まれており、実際の参照を探す前に削除する必要があります。そうしないと、=A1&"A1"正規表現が壊れます
  • ワークシート名は、\ / ? を除き、最大 31 文字です。* [ ] :
  • 外部参照内のワークシート名は bang で終わる必要があります=Sheet1!A1
  • 外部参照のワークブック名​​は角かっこで囲む必要があります=[Book1.xlsx]Sheet1!A1
  • 参照が閉じたブック内の範囲への参照である場合に Excel が追加するブック パスは、常に一重引用符で囲まれ、ブック名の角かっこの左側にあります。'C:\[Book1.xlsx]Sheet1'!A1
  • 一部の文字 (区切りのないスペースなど) により、Excel はブックとワークシートの名前を単一引用符で囲んだ外部参照を作成しますが、どの文字が具体的にわかりません。 ='[Book 1.xlsx]Sheet 1'!A1
  • R1C1 表記が有効になっている場合Range.Formulaでも、参照は A1 表記で返されます。Range.FormulaR1C1参照を R1C1 表記で返します。
  • 3D 参照スタイルにより、1 つのワークブックでさまざまなシート名を使用できます=SUM([Book5]Sheet1:Sheet3!A1)
  • 名前付き範囲は数式で指定できます。
    • 名前の最初の文字は、文字、アンダースコア (_)、またはバックスラッシュ (\) でなければなりません。名前の残りの文字は、文字、数字、ピリオド、およびアンダースコア文字にすることができます。
    • 大文字と小文字の "C"、"c"、"R"、または "r" を定義名として使用することはできません。これらはすべて、現在選択されているセルの行または列を選択する際の省略形として使用されるためです。それらを [名前] または [移動先] テキスト ボックスに入力します。
    • 名前は、Z$100 や R1C1 などのセル参照と同じにすることはできません。
    • 名前の一部としてスペースを使用することはできません。
    • 名前の長さは最大 255 文字です。
    • 名前には大文字と小文字を含めることができます。Excel では、名前の大文字と小文字が区別されません。

これが、テスト用の VBA プロシージャにラップされた、私が思いついたものです。名前も処理するようにコードを更新しました。

Sub ReturnFormulaReferences()

    Dim objRegExp As New VBScript_RegExp_55.RegExp
    Dim objCell As Range
    Dim objStringMatches As Object
    Dim objReferenceMatches As Object
    Dim objMatch As Object
    Dim intReferenceCount As Integer
    Dim intIndex As Integer
    Dim booIsReference As Boolean
    Dim objName As Name
    Dim booNameFound As Boolean

    With objRegExp
        .MultiLine = True
        .Global = True
        .IgnoreCase = True
    End With

    For Each objCell In Selection.Cells
        If Left(objCell.Formula, 1) = "=" Then

            objRegExp.Pattern = "\"".*\"""
            Set objStringMatches = objRegExp.Execute(objCell.Formula)

            objRegExp.Pattern = "(\'.*(\[.*\])?([^\:\\\/\?\*\[\]]{1,31}\:)?[^\:\\\/\?\*\[\]]{1,31}\'\!" _
            & "|(\[.*\])?([^\:\\\/\?\*\[\]]{1,31}\:)?[^\:\\\/\?\*\[\]]{1,31}\!)?" _
            & "(\$?[a-z]{1,3}\$?[0-9]{1,7}(\:\$?[a-z]{1,3}\$?[0-9]{1,7})?" _
            & "|\$[a-z]{1,3}\:\$[a-z]{1,3}" _
            & "|[a-z]{1,3}\:[a-z]{1,3}" _
            & "|\$[0-9]{1,7}\:\$[0-9]{1,7}" _
            & "|[0-9]{1,7}\:[0-9]{1,7}" _
            & "|[a-z_\\][a-z0-9_\.]{0,254})"
            Set objReferenceMatches = objRegExp.Execute(objCell.Formula)

            intReferenceCount = 0
            For Each objMatch In objReferenceMatches
                intReferenceCount = intReferenceCount + 1
            Next

            Debug.Print objCell.Formula
            For intIndex = intReferenceCount - 1 To 0 Step -1
                booIsReference = True
                For Each objMatch In objStringMatches
                    If objReferenceMatches(intIndex).FirstIndex > objMatch.FirstIndex _
                    And objReferenceMatches(intIndex).FirstIndex < objMatch.FirstIndex + objMatch.Length Then
                        booIsReference = False
                        Exit For
                    End If
                Next

                If booIsReference Then
                    objRegExp.Pattern = "(\'.*(\[.*\])?([^\:\\\/\?\*\[\]]{1,31}\:)?[^\:\\\/\?\*\[\]]{1,31}\'\!" _
                    & "|(\[.*\])?([^\:\\\/\?\*\[\]]{1,31}\:)?[^\:\\\/\?\*\[\]]{1,31}\!)?" _
                    & "(\$?[a-z]{1,3}\$?[0-9]{1,7}(\:\$?[a-z]{1,3}\$?[0-9]{1,7})?" _
                    & "|\$[a-z]{1,3}\:\$[a-z]{1,3}" _
                    & "|[a-z]{1,3}\:[a-z]{1,3}" _
                    & "|\$[0-9]{1,7}\:\$[0-9]{1,7}" _
                    & "|[0-9]{1,7}\:[0-9]{1,7})"
                    If Not objRegExp.Test(objReferenceMatches(intIndex).Value) Then 'reference is not A1
                        objRegExp.Pattern = "^(\'.*(\[.*\])?([^\:\\\/\?\*\[\]]{1,31}\:)?[^\:\\\/\?\*\[\]]{1,31}\'\!" _
                        & "|(\[.*\])?([^\:\\\/\?\*\[\]]{1,31}\:)?[^\:\\\/\?\*\[\]]{1,31}\!)" _
                        & "[a-z_\\][a-z0-9_\.]{0,254}$"
                        If Not objRegExp.Test(objReferenceMatches(intIndex).Value) Then 'name is not external
                            booNameFound = False
                            For Each objName In objCell.Worksheet.Parent.Names
                                If objReferenceMatches(intIndex).Value = objName.Name Then
                                    booNameFound = True
                                    Exit For
                                End If
                            Next
                            If Not booNameFound Then
                                objRegExp.Pattern = "^(\'.*(\[.*\])?([^\:\\\/\?\*\[\]]{1,31}\:)?[^\:\\\/\?\*\[\]]{1,31}\'\!" _
                                & "|(\[.*\])?([^\:\\\/\?\*\[\]]{1,31}\:)?[^\:\\\/\?\*\[\]]{1,31}\!)"
                                For Each objName In objCell.Worksheet.Names
                                    If objReferenceMatches(intIndex).Value = objRegExp.Replace(objName.Name, "") Then
                                        booNameFound = True
                                        Exit For
                                    End If
                                Next
                            End If
                            booIsReference = booNameFound
                        End If
                    End If
                End If

                If booIsReference Then
                    Debug.Print "  " & objReferenceMatches(intIndex).Value _
                    & " (" & objReferenceMatches(intIndex).FirstIndex & ", " _
                    & objReferenceMatches(intIndex).Length & ")"
                End If
            Next intIndex
            Debug.Print

        End If
    Next

    Set objRegExp = Nothing
    Set objStringMatches = Nothing
    Set objReferenceMatches = Nothing
    Set objMatch = Nothing
    Set objCell = Nothing
    Set objName = Nothing

End Sub

誰かがこれを壊したり改善したりできますか? Excel の数式構文に関する完全なドキュメントがなければ、これが正しいかどうかを知ることは困難です。

ありがとう!

4

4 に答える 4

3

jtolle は私を正しい方向に導いてくれました。私が知る限り、これが私がやろうとしていたことです。私はテストしてきましたが、うまくいくようです。

stringOriginFormula = rangeOrigin.Formula
rangeOrigin.Cut rangeDestination
rangeOrigin.Formula = stringOriginFormula

jtolleさん、ありがとうございます!

于 2009-12-18T00:28:16.930 に答える