【问题标题】:How do I read the formatted textual representation of a cell in Excel如何在 Excel 中读取单元格的格式化文本表示
【发布时间】:2011-05-09 00:30:32
【问题描述】:

我正在使用 Excel 的 COM 接口,我想获取单元格的格式化文本表示,而不是真正的底层值。

例如,假设单元格包含数字1.23456,并且用户指定了带 1 个小数位的数字格式。然后我希望能够读取字符串"1.2"。我知道我可以使用Range.Text,但这在几个重要方面都失败了。 Range.Text 返回用户在工作表视图中看到的内容,因此如果单元格被隐藏,则返回空字符串。如果单元格的宽度较低,则返回截断的字符串。 Range.Text 也下降了,因为它被限制为 1024 个字符。

另一个用例是当单元格评估为错误时,例如#DIV/0!#NAME?#REF! 等。我知道我可以读取Range.Value 并测试变体是否为varError 类型(我使用的是Delphi,在VBA 中它将是vbError)。我不知道如何获取文本表示 #DIV/0! 等。Range.Text 再次返回此,但如果单元格被隐藏或太窄则不会。

编辑

我认为 Range.Text 的限制实际上是 255 个字符。

【问题讨论】:

    标签: excel com


    【解决方案1】:

    以 Steven 的回答为基础:试试这个 VBA 代码。
    由于排队要求,它不能正确处理会计格式,但无论如何你都不清楚在这种情况下你想做什么。

        Sub testing()
        Dim oRng As Range
        Dim var As Variant
        Set oRng = Range("a3")
        If IsError(oRng) Then
            var = cstrError(oRng.Value)
        Else
        var = oRng.Value2
        If IsNumeric(var) Then var = Format(var, oRng.NumberFormatLocal)
        End If
        MsgBox Len(var) & " " & var
    End Sub
    Function cstrError(vError As Variant) As String
        Select Case CLng(vError)
        Case xlErrDiv0
            cstrError = "#DIV/0!"
        Case xlErrNA
            cstrError = "#N/A"
        Case xlErrName
            cstrError = "#NAME?"
        Case xlErrNull
            cstrError = "#NULL!"
        Case xlErrNum
            cstrError = "#NUM!"
        Case xlErrValue
            cstrError = "#VALUE!"
        Case xlErrRef
            cstrError = "#REF!"
        Case Else
            cstrError = "#N/A"
        End Select
    End Function
    

    【讨论】:

    • 当单元格包含超过 255 个字符时会失败
    • 它的 Format 函数有 255 个字符的限制 - 尝试修改版本,如果值是数字则只使用 format。
    • 这看起来很有希望,但 Format 是一个 VBA 函数。我正在使用 COM(它是一个 COM 插件),我不确定是否有可用的等效功能。
    • 如果 Delphi 没有 VB6 的 Format 等效项,那么您可以使用 Application.WorksheetFunction.Text(var, oRng.NumberFormatLocal) 而不是 Format(var, oRng.NumberFormatLocal) 。它的效率较低,但应该可以工作。
    • 最后一个小问题。您对为什么 NumberFormatLocal 优于 NumberFormat 有一个简洁的解释吗?
    【解决方案2】:

    获取不包含错误的隐藏单元格的文本:

    Application.WorksheetFunction.Text(the_cell.Value, the_cell.NumberFormat)
    

    如果是错误,则失败。所以你可能想先检查一下:

    Application.WorksheetFunction.IsError(the_cell)
    

    不幸的是,由于 VBA 或 COM 对象不提供 Error.Type 函数,因此很难弄清楚您遇到了什么样的错误。解决此问题的方法是将该公式写入同一张工作表的另一个单元格中并读取其值。

    【讨论】:

    • 同样,当单元格包含超过 255 个字符时,此操作将失败。我越是尝试对此进行调查,我就越怀疑这根本不可能。
    【解决方案3】:

    非常感谢 Charles 的回答和帮助 cmets。我现在拼凑了一个我需要的 Delphi/COM 版本,如下所示:

    function GetCell(const Sheet: ExcelWorksheet; const Row, Col: Integer): string;
    
      function ErrorText(const Cell: ExcelRange; hr: HRESULT): string;
      const
        ErrorBase=HRESULT($800A0000);
      var
        i: Integer;
      begin
        Result := Cell.Text;
        for i := 1 to Length(Result) do begin
          if Result[i]<>'#' then begin
            exit;
          end;
        end;
        if hr=ErrorBase or xlErrDiv0 then begin
          Result := '#DIV/0!';
        end else if hr=ErrorBase or xlErrNA then begin
          Result := '#N/A';
        end else if hr=ErrorBase or xlErrName then begin
          Result := '#NAME?';
        end else if hr=ErrorBase or xlErrNull then begin
          Result := '#NULL!';
        end else if hr=ErrorBase or xlErrNum then begin
          Result := '#NUM!';
        end else if hr=ErrorBase or xlErrRef then begin
          Result := '#REF!';
        end else if hr=ErrorBase or xlErrValue then begin
          Result := '#VALUE!';
        end else begin
          Result := 'an error';
        end;
      end;
    
    var
      Cell: ExcelRange;
      hr: HRESULT;
    
    begin
      Cell := GetCellAsRange(Sheet, Row, Col);
      if VarIsError(Cell.Value, hr) then begin
        raise ECellValueError.CreateFmt(
          'Cell %s contains %s.',
          [R1C1toA1(Row,Col), ErrorText(Cell, hr)]
        );
      end else if VarIsNumeric(Cell.Value) then begin
        Result := Sheet.Application.WorksheetFunction.Text(Cell.Value, Cell.NumberFormatLocal);
      end else begin
        Result := ConvertToString(Cell.Value);
      end;
    end;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-01-10
      • 2023-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-26
      • 2017-05-31
      相关资源
      最近更新 更多