如何在Excel中读取单元格的格式化文本表示

时间:2010-11-12 11:16:02

标签: excel com

我正在使用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个字符。

3 个答案:

答案 0 :(得分:3)

以史蒂文的答案为基础:试试这个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

答案 1 :(得分:2)

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

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

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

Application.WorksheetFunction.IsError(the_cell)

不幸的是,很难弄清楚你有什么样的错误,因为Error.Type函数不能从VBA或COM对象获得。解决这个问题的方法是将该公式写在同一张纸上的另一个单元格中并读取其值。

答案 2 :(得分:2)

非常感谢Charles的回答和有用的评论。我现在拼凑了我需要的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;