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