How do I read the formatted textual representation

2019-04-11 00:51发布

问题:

I'm using the COM interface to Excel and I would like to get hold of the formatted textual representation of a cell rather than the true underlying value.

For example, suppose the cell contains the number 1.23456 and the user has specified the number format with 1 decimal place. Then I'd like to be able to read the string "1.2". I know that I can use Range.Text but this fails in a couple of significant ways. Range.Text returns what the user sees in the view of the sheet and so if the cell is hidden then the empty string is returned. If the cell's width is low then a truncated string is returned. Range.Text also falls down because it is limited to 1024 characters.

Another use case is when the cell evaluates to an error, e.g. #DIV/0!, #NAME?, #REF! etc. I know that I can read Range.Value and test if the variant is type varError (I'm using Delphi, in VBA it would be vbError). What I can't figure out is how to get hold of the text representation #DIV/0! etc. Again Range.Text returns this, but not if the cell is hidden or is too narrow.

EDIT

I think that the limit on Range.Text is actually 255 characters.

回答1:

Building on Steven's answer: try this VBA code.
It does not handle the Accounting format properly because of the lining-up requirement, but its not clear what you would want to do in that case anyway.

    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


回答2:

To get the text of a hidden cell that does not contain an error:

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

If it's an error, this fails. So you may want to first check:

Application.WorksheetFunction.IsError(the_cell)

Unfortunately, it's difficult to figure out what kind of error you have as the Error.Type function is not available from VBA or COM object. A work around for this would be to write that formula in another cell on the same sheet and read its value.



回答3:

Thanks a lot Charles for your answer and helpful comments. I've now pieced together a Delphi/COM version of what I need which is as follows:

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;


标签: excel com