.text、.value 和 .value2 之间有什么区别?

What is the difference between .text, .value, and .value2?

提问人:Chris 提问时间:6/28/2013 最后编辑:ΩmegaManChris 更新时间:1/7/2023 访问量:295960

问:

、 和 和有什么不一样?比如什么时候应该使用 target.text、target.value 和 target.value2?.text.value.value2

Excel VBA

评论

0赞 Bathsheba 6/28/2013
如果 Target.Value 不能强制转换为字符串,则 LCase(Target.Value) 将失败,因为 LCase 需要参数的字符串。您应该按照我的答案首先检查 VarType。另请注意,您可以改用 UCase 并直接与“HLO”进行比较:对文字进行操作没有多大意义。
0赞 Chris 6/30/2013
感谢您提供有关 VarType 的信息。至于 LCase 或 UCase,我使用哪一个真的无关紧要。有些人将其输入为 hlo,而另一些人则将其输入为 HLO。从我所看到的情况来看,小写的似乎更频繁地使用。

答:

26赞 Bathsheba 6/28/2013 #1

target.Value会给你一个类型Variant

target.Value2也会给你一个类型,但 a 被强制为VariantDateDouble

target.Text尝试强制执行 A,如果基础无法强制执行到类型,则将失败StringVariantString

最安全的做法是

Dim v As Variant
v = target.Value 'but if you don't want to handle date types use Value2

在尝试显式强制之前,请检查变体使用的类型。VBA.VarType(v)

62赞 Kazimierz Jawor 6/28/2013 #2

除了 Bathsheba 的回答和 MSDN 信息之外:

。值
。值 2
.发短信

您可以分析下表,以便更好地了解这三个属性之间的差异。

enter image description here

评论

6赞 Kazimierz Jawor 6/28/2013
@Chris,始终用作标准属性 - 用于文本和数字。当您想到日期和一些数字时使用。如果您需要保留单元格/范围中任何内容的格式,请始终使用。所以,你的问题示例是否正确!.Value.Value2.Text
2赞 Katrin 3/26/2018
为什么日期从 10:12 更改为 10:05?错字?
4赞 Kazimierz Jawor 3/26/2018
我认为这只是生成结果和制作屏幕截图之间的时间
305赞 Charles Williams 6/28/2013 #3

.Text为您提供一个字符串,表示单元格屏幕上显示的内容。使用通常是一个坏主意,因为你可以得到.Text####

.Value2为您提供单元格的基础值(可以是空、字符串、错误、数字(双精度)或布尔值)

.Value为您提供相同,除非单元格格式为货币或日期,否则它会为您提供VBA货币(可能会截断小数位)或VBA日期。.Value2

使用 or 通常是一个坏主意,因为您可能无法从单元格中获得真正的值,而且它们比.Value.Text.Value2

有关更广泛的讨论,请参阅我的文本 vs 价值 vs 价值 2

评论

6赞 Charles Williams 1/22/2015
我可能会使用 Format 来控制如何将数字转换为字符串:var = Format(Range(“a1”)。值 2,“#”)
2赞 Martin F 4/25/2015
我希望这不是一个单独的问题,而是:什么是默认值?OP 含糊其辞地声称省略 text/value/value2 是有问题的,但它肯定是默认为其中之一吗?
1赞 Charles Williams 4/25/2015
默认值为 。价值
3赞 Charles Williams 8/31/2017
@Mat的杯子 - 问题是 Excel 没有真正的日期数据类型 - excel 日期和时间只是双倍值,取决于用户应用或更改的任何格式以显示为日期、时间或货币或只是一个数字。因此,Value 正在强制将 Excel 双精度转换为 VBA 日期,但 Value2 没有进行任何强制......对于日期,只要代码理解它依赖于可更改的格式,强制双倍日期可能不会造成任何损害:无论哪种方式都有利弊 - 我们真正需要的是更多的本机 Excel 数据类型来避免这个问题。
2赞 ChrisB 6/20/2018
当我想在没有类型转换的情况下将单元格值设置为等于另一个单元格时(例如,不将存储为文本的数字转换为数字),我使用这个: .Format$(Range.Value2, Range.NumberFormat)
11赞 silkfire 9/8/2015 #4

关于 C# 中的约定。假设您正在读取包含日期的单元格,例如 2014-10-22。

使用时:

.Text,您将获得日期的格式表示形式,如屏幕上的工作簿所示:
2014-10-22。此属性的类型始终是,但可能并不总是返回令人满意的结果。
string

.Value,编译器尝试将日期转换为对象: {2014-10-22 00:00:00} 很可能仅在读取日期时有用。DateTime

.Value2,为您提供单元格的真实基础值。对于日期,它是日期序列:41934。此属性可以具有不同的类型,具体取决于单元格的内容。但是,对于日期序列,类型为 。double

因此,您可以检索并存储单元格的值,或者,但请注意,该值将始终具有某种您必须执行操作的先天类型。dynamicvarobject

dynamic x = ws.get_Range("A1").Value2;
object  y = ws.get_Range("A1").Value2;
var     z = ws.get_Range("A1").Value2;
double  d = ws.get_Range("A1").Value2;      // Value of a serial is always a double
4赞 user4039065 6/15/2018 #5

.文本是格式化单元格的显示值; 。Value 是单元格的值,可能使用日期或货币指示符进行扩充;Value2 是去除任何无关信息的原始基础值。

range("A1") = Date
range("A1").numberformat = "yyyy-mm-dd"
debug.print range("A1").text
debug.print range("A1").value
debug.print range("A1").value2

'results from Immediate window
2018-06-14
6/14/2018 
43265 

range("A1") = "abc"
range("A1").numberformat = "_(_(_(@"
debug.print range("A1").text
debug.print range("A1").value
debug.print range("A1").value2

'results from Immediate window
   abc
abc
abc

range("A1") = 12
range("A1").numberformat = "0 \m\m"
debug.print range("A1").text
debug.print range("A1").value
debug.print range("A1").value2

'results from Immediate window
12 mm
12
12

如果要处理单元格的值,则读取原始 .Value2 比 稍快。值或 .发短信。如果要查找错误,则 .text 将返回类似 text 的内容,并且可以与字符串进行比较,而 .值和 .Value2 将扼杀将其返回值与字符串进行比较。如果您对数据应用了一些自定义单元格格式,则 .在生成报表时,文本可能是更好的选择。#N/A

1赞 pgSystemTester 6/5/2019 #6

出于好奇,我想看看对.在对类似过程进行了大约 12 次尝试后,我看不到速度有任何显着差异,因此我总是建议使用 .我使用下面的代码运行了一些具有各种范围的测试。ValueValue2Value

如果有人看到任何与性能相反的地方,请发帖。

Sub Trial_RUN()
    For t = 0 To 5
        TestValueMethod (True)
        TestValueMethod (False)
    Next t

End Sub




Sub TestValueMethod(useValue2 As Boolean)
Dim beginTime As Date, aCell As Range, rngAddress As String, ResultsColumn As Long
ResultsColumn = 5

'have some values in your RngAddress. in my case i put =Rand() in the cells, and then set to values
rngAddress = "A2:A399999" 'I changed this around on my sets.



With ThisWorkbook.Sheets(1)
.Range(rngAddress).Offset(0, 1).ClearContents


beginTime = Now

For Each aCell In .Range(rngAddress).Cells
    If useValue2 Then
        aCell.Offset(0, 1).Value2 = aCell.Value2 + aCell.Offset(-1, 1).Value2
    Else
        aCell.Offset(0, 1).Value = aCell.Value + aCell.Offset(-1, 1).Value
    End If

Next aCell

Dim Answer As String
 If useValue2 Then Answer = " using Value2"

.Cells(Rows.Count, ResultsColumn).End(xlUp).Offset(1, 0) = DateDiff("S", beginTime, Now) & _
            " seconds. For " & .Range(rngAddress).Cells.Count & " cells, at " & Now & Answer


End With


End Sub

enter image description here

评论

0赞 Charles Williams 4/2/2021
你的时间完全被引用细胞的开销所淹没(逐个细胞的行走对性能来说是一场灾难)。尝试使用分配给变体的大范围单元格并创建二维变体 arry。
0赞 pgSystemTester 4/3/2021
@CharlesWilliams是的,你是对的。我称之为 CRINGE CODE,意思是它是我在知道其他事情(即数组的重要性)之前写的代码,回想起来,我......你猜对了......畏缩。无论如何,谢谢你的提示。我以后可能会重新发布一些东西。
0赞 Excel Hero 4/7/2022
当日期和时间包含在源数据中时,差异将更好地显示出来。 更快。.Value2
2赞 Excel Hero 4/7/2022 #7

Value2几乎总是读取或写入 Excel 单元格或范围的最佳选择......来自 VBA。

Range.Value2 '<------Best way

以下各项都可用于从某个区域读取

v = [a1]
v = [a1].Value
v = [a1].Value2
v = [a1].Text 
v = [a1].Formula
v = [a1].FormulaR1C1

以下各项都可用于写入范围:

[a1] = v
[a1].Value = v
[a1].Value2 = v
[a1].Formula = v
[a1].FormulaR1C1 = v

要从大范围内读取多个值,或写入多个值,一次性完成整个操作比逐个单元格要快几个数量级:

arr = [a1:z999].Value2

如果 是 Variant 类型的变量,则上面的行实际上创建了一个 26 列宽和 999 行高的变体的 OLE SAFEARRAY 结构,并将 Variant 指向内存中的 SAFEARRAY 结构arrarr

[a1].Resize(UBound(arr), UBound(arr, 2).Value2 = arr

上面的一行将整个数组一次性写入工作表,无论数组有多大(只要它适合工作表)。

range 对象的默认属性是属性。因此,如果未为该范围指定任何属性,则默认情况下会以静默方式引用该属性。ValueValue

但是,是访问范围值的最快属性,读取它时返回真正的基础单元格值。它忽略数字格式、日期、时间和货币,并始终以 VBA Double 数据类型返回数字。由于尝试做更少的工作,它的执行速度比 .Value2Value2Value

另一方面,该属性检查单元格值是否具有“日期”或“时间”的数字格式,并在这些情况下返回 VBA Date 数据类型的值。如果您的 VBA 代码将使用 Date 数据类型,则使用该属性检索它们可能是有意义的。将VBA Date数据类型写入单元格将自动使用相应的日期或时间数字格式设置单元格的格式。和 将 VBA 货币数据类型写入单元格会自动将货币数字格式应用于相应的单元格。ValueValue

同样,检查单元格货币格式,然后 返回 VBA Currency 数据类型的值。这可能导致 精度损失,因为 VBA Currency 数据类型只能识别 小数点后四位(因为 VBA Currency 数据类型实际上只是一个 64 位整数,缩放为 10000),因此值四舍五入到四位, 至多。奇怪的是,这个精度被削减到只有两位小数 用于将 VBA 货币变量写入工作表范围时的位置。ValueValue

只读属性始终返回 VBA String 数据类型。返回的值是每个单元格中显示的内容的文本表示形式,包括“数字格式”、“日期”、“时间”、“货币”和“错误”文本。这不是将数值导入 VBA 的有效方法,因为需要隐式或显式强制。 当列太细时会返回 #######,当调整某些行高时,它会更慢。 与 和 相比,总是非常慢。但是,由于保留单元格值的格式化外观,因此可能很有用,特别是对于使用格式正确的文本值填充用户窗体控件。TextRange.TextTextTextValueValue2TextText

同样,两者始终以 VBA 字符串数据类型的形式返回值。如果单元格包含公式,则返回其 A1 样式表示形式并返回其 R1C1 表示形式。如果一个单元格有一个硬值而不是一个公式,那么两者都忽略所有格式,并返回真正的基础单元格值,就像做的那样......然后执行进一步的步骤,将该值转换为字符串。同样,这不是将数值导入 VBA 的有效方法,因为需要隐式或显式强制。但是,并且必须用于读取单元格 公式。它们应该用于将公式写入单元格。FormulaFormulaR1C1FormulaFormulaR1C1FormulaFormulaR1C1Value2FormulaFormulaR1C1

如果单元格 A1 包含具有货币数字格式的数值 100.25 $#,##0.00_);($#,##0.00) 请考虑以下几点:

MsgBox [a1].Value                   'Displays:  100.25
MsgBox TypeName([a1].Value)         'Displays: Currency
 
MsgBox [a1].Value2                  'Displays:  100.25
MsgBox TypeName([a1].Value2)        'Displays: Double
 
MsgBox [a1].Text                    'Displays: $ 100.25
MsgBox TypeName([a1].Text)          'Displays: String
 
MsgBox [a1].Formula                 'Displays: 100.25
MsgBox TypeName([a1].Formula)       'Displays: String
 
MsgBox [a1].FormulaR1C1             'Displays: 100.25
MsgBox TypeName([a1].FormulaR1C1)   'Displays: String