【问题标题】:Search formula for cell references in VBA在 VBA 中搜索单元格引用的公式
【发布时间】:2018-11-12 15:12:18
【问题描述】:

在 VBA 中,我想搜索一个 excel 公式(字符串)来查找单元格引用。

具体来说,我想在字符串中找到存在相对单元格引用(任何相对单元格引用,而不是特定单元格引用)或混合单元格引用的位置。

  • 我不需要查找绝对单元格引用,尽管我可以检查并忽略那些。
  • 我不介意参考文献是否在另一张纸上,我很高兴在 !符号。
  • 我需要确保它不会在字符串或工作表名称或数据名称中找到看起来像单元格引用的内容。

我该怎么做?(这是主要问题)

我的想法:

我可以看到如何找到混合单元格引用 - 我很确定 $ 符号只能出现在混合单元格引用、绝对引用、内部工作表名称或内部字符串中(有人可以确认吗?) ,因此使用正确的正则表达式或算法,您可以找到所有这些情况,然后只需检查它是否是绝对单元格引用并忽略它。

但是如何找到任何和所有相关的单元格引用?我唯一的想法与上述类似。除了单元格引用之外,在 Excel 公式(工作表名称之外或字符串内部)中是否有任何时候在字母后面有一个数字?任何公式名称或任何东西?我能想到的唯一另一个是定义的数据名称,但我不确定您是否可以在公式中使用它们,尤其是条件格式公式)。谁能想到其他时间?

有人有什么想法吗?

【问题讨论】:

  • 查看Range.Precedents
  • 您对正则表达式感兴趣吗?
  • 谢谢马修。我提到我有一个公式字符串,那是因为它来自条件格式。尽管如此,我还是可以将公式放在一个空单元格中,跟踪先例,获取公式中的单元格列表,然后专门搜索这些单元格。这是一个有趣的想法,虽然是一个相当复杂的想法。谢谢
  • 嗨 Kubie,是的,我会对 RegEx 非常感兴趣,尽管我认为关于如何搜索任何和所有相关单元格引用的要点很重要,我不知道是否我的建议会奏效。
  • 一条关于您的 cmets 的评论。不要写“Hi #Name”,而是考虑在评论开头使用@Name。在您的情况下,可能是 Kubie 和 Mathieu 从未阅读过您的评论

标签: excel vba string formula


【解决方案1】:

我不确定你的用例是什么,但你可以尝试一下这个函数中的一些内容:

这个项目使用 Early Binding - 你必须设置一个引用:

Microsoft VBScript Regular Expressions 5.5
Function findCellReferences(vTestVal As Variant) As Variant

    'Check if vTestVal is a range, if so, convert to string
    If TypeName(vTestVal) = "Range" Then
        vTestVal = vTestVal.Formula
    ElseIf TypeName(vTestVal) <> "String" Then
        findCellReferences = "Type-Err!"
        Exit Function
    End If

    Dim oMatches As MatchCollection

    With New RegExp
        .Pattern = "(?:^|[,!(=\s])((?:\$?[A-Z]{1,3}\$?\d+(?::\$?[A-Z]{1,3}\$?\d+)?|" & _
                "\$?[a-z]{1,3}:\$?[a-z]{1,3}|\$?\d+:\$?\d+))(?:$|[\s,)])"
        .IgnoreCase = True
        .Global = True
        If .test(vTestVal) Then
            Dim i As Long, retArr()
            Set oMatches = .Execute(vTestVal)
            With oMatches
                ReDim retArr(.Count - 1)
                For i = 0 To .Count - 1
                    retArr(i) = .Item(i).SubMatches(0)
                Next
            End With
            findCellReferences = Join(retArr, ",")
        Else
            findCellReferences = False
        End If
    End With

End Function

这个函数可以接受两种不同的数据类型:

  1. 范围
  2. 字符串

这允许您将其用作工作表函数来测试公式的文本值,或者您可以使用它直接测试输入字符串。

这是检查单元格的返回:

以下是上述公式的样子:

这也可以在 VBA 中使用:

Sub Test()

    Rem: Passing a string argument
    Debug.Print findCellReferences("A1:B1, $C1")
    ' Prints: A1:B1,$C1

End Sub

分解正则表达式:Regex101

(?:^|[,!(=\s])((?:\$?[A-Z]{1,3}\$?\d+(?::\$?[A-Z]{1,3}\$?\d+)?|\$?[a-z]{1,3}:\$?
[a-z]{1,3}|\$?\d+:\$?\d+))(?:$|[\s,)])
  • (?:^|[,(=\s]) 要求在您的比赛之前发生以下情况之一
    • ^ 字符串开始;或
    • 单个字符,可以是
      • , 逗号(在公式中很有用)
      • ! 感叹号(用于Sheet! 引用)
      • ( 左括号(在公式中很有用)
      • = 文字等号(在公式中很有用)
      • \s 一个空白字符
  • (...) 将返回您的值的捕获组(三个选项之一)
    • \$?[A-Z]{1,3}\$?\d+(?::\$?[A-Z]{1,3}\$?\d+)?不是整行/列
      • \$ 表示绝对引用(列),然后是 ? 使其可选
      • [A-Z] 任何字母的字符类,+ 一次或多次
      • \$ 用于绝对引用(行),然后是 ? 使其可选
      • \d 任意数字,+ 一次或多次
      • (?:...) 非捕获组匹配一个范围的范围(如A1:B1
        • 这使用与上述相同的方法
        • 后跟?,使整个非捕获组可选
    • \$?[a-z]{1,3}:\$?[a-z]{1,3} 整列,例如A:C
    • \$?\d+:\$?\d+整行,如1:3
  • (?:$|[\s,)]) 要求在您的比赛之后发生以下情况之一
    • $ 字符串结尾;或
    • 单个字符,它是
      • \s 一个空白字符
      • ,逗号
      • )右括号

学分:

tripleee的建议:
- 使用字符类 [xyz] 而不是 OR 语句 (?:x|y|z)
- 更好的故障缩进
- 语法用法

Makyen的建议:
- 支持整行1:4 和整列A:C
- 通过检查 Excel 的最大列限制 [a-z]{1,3}(而不是 [a-z]+)来限制 FPs

【讨论】:

  • 嗨,K. Davis,您确实给了我很多东西可以浏览和试验。在此之前,我只能深深感谢您抽出时间和付出努力。我不知道@tripleee 对代码的更改会产生什么影响(如果有的话),但我也会看看这些。
  • 我在发表这篇文章后咨询了他——当然欢迎他的编辑@JamesCarlyle-Clarke
  • 这会排除碰巧看起来像单元格引用的文字字符串位吗?
  • 这可以被公式中的removing the \s 否定。 OP 只需要防止在合法范围内出现空格@chrisneilsen - 问题是 VBScript RegEx 不支持环视。
  • 嗨 K. Davis,这是一件非常漂亮的事情,它似乎找到了传递给函数的任何引用,例如 SUM(H7:M7)。我还没有测试所有的边缘情况(例如,带有字母后跟数字的自定义函数名称,类似的命名范围)。问题是它似乎没有在“A3+B4”中找到任何一个单元格引用(有或没有等号)。正则表达式不是我的专业领域,所以我无法立即看到我将如何改进它。我也没有真正得到你上面的最后一条评论,但听起来你是说我应该删除字符串以外的任何空格?
猜你喜欢
  • 1970-01-01
  • 2020-01-26
  • 2015-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-30
相关资源
最近更新 更多