Empty, Null, Nothing, Missing, prázdný řetězec a buňka

Řečeno slovní hříčkou, pojmy uvedené v titulku mají společného „všechno a nic“. Každý z nich je vyjádřením stavu prázdné proměnné, a to podle datového typu či kontextu.

Empty

  • vyjadřuje neinicializovanou proměnnou typu Variant (její výchozí hodnotu)
  • ve VBA klíčové slovo Empty, funkcí IsEmpty testujeme například prázdnou buňku
  • ve VBA funkce VarType vrací 0 (vbEmpty)
  • dle kontextu je za Empty považována jak nula, tak prázdný řetězec
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
Sub TestEmpty()

    Dim a, x

    a = 3

    'správně
    a = Empty
   
    'špatně
    'a = vbEmpty
    'vbEmpty ... 0 (datový typ Long)
    'běžně jen pro testování VarType
   
    '0
    x = VarType(a)
   
    'True
    x = VarType(a) = vbEmpty
   
    'Allen Browne:
    'obojí True
    Debug.Print Empty = 0
    Debug.Print Empty = ""
   
    '-1 (True)
    x = Not a
   
    '1
    x = a ^ 0
   
    '0
    x = a And True
   
    'test na prázdnou buňku, True
    x = ActiveCell = Empty
    'lépe, True
    x = IsEmpty(ActiveCell)

End Sub

Null (no valid data, C NULL)
http://cs.wikipedia.org/wiki/NULL

  • indikuje neznámou hodnotu pro datový typ Variant
  • v databázi položka pole, na níž se nevyskytují žádná data
  • ve VBA klíčové slovo Null, testujeme prostřednictvím funkce IsNull
  • ve VBA funkce VarType vrací 1 (vbNull)
  • ve VBA Chr(0), resp. vbNullChar používán jako ukončovací znak řetězce (C NULL v programovacím jazyce C, typicky API funkce), na listu nelze zadat funkci ZNAK(0)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
Sub TestNull()

    'http://cs.wikipedia.org/wiki/NULL
   
    Dim x, y, z
   
    'špatně
    'z = vbNull
    'vbNull ... 1 (datový typ Long)
    'běžně jen pro testování VarType

    'znak Null (datový typ String)
    'odpovídá NULL v jazyce C
    z = Chr(0)
    'ekvivalent
    z = vbNullChar
    '1
    x = Len(z)
   
    'správně
    z = Null
   
    '1
    x = VarType(z)
   
    'True
    x = VarType(z) = vbNull

    'Null
    x = 1 + z

    'y
    x = "y" & z

    'False
    x = False And z

    'Null v porovnání s Null nevrací True
    x = z = z

    'True
    x = IsNull(z)
   
    'bez chyby, ale pravděpodobně bez účinku
    ActiveCell = Null
    'podobně
    'ActiveCell = Chr(0)
    'na listu nelze zadat ZNAK(0)
   
    Dim aPole(1 To 1)
    aPole(1) = Null
    'funkce listu TRANSPOZICE neumí Null převádět
    ActiveCell = WorksheetFunction.Transpose(aPole)
   
    'chybný test na prázdnou buňku, False
    x = IsNull(ActiveCell)
   
    'správný test na prázdnou buňku, True
    x = IsEmpty(ActiveCell)

End Sub

Nothing

  • vyjadřuje neinicializovanou (nepřiřazenou) objektovou proměnnou (její výchozí hodnotu)
  • platí pro proměnné deklarované jako As Object, Workbook, Worksheet, Range, UserForm, Connection, …
  • ve VBA ruší vazbu (asociaci) objektové proměnné na aktuální objekt (Set rngBunka = Nothing), čímž také uvolňuje systémové zdroje (alokovanou paměť)
  • testujeme operátorem Is (rngBunka Is Nothing), tj. VBA nezná funkci IsNothing
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Sub TestNothing()

    Dim rngBunka As Range

    Dim blnRes As Boolean

    'True
    blnRes = rngBunka Is Nothing

    'přiřazení buňky A1 aktivního listu
    'do objektové proměnné (typu Range)
    Set rngBunka = Range("A1")

    'False
    blnRes = rngBunka Is Nothing

    'ruší vazbu objektové proměnné
    'na buňku A1 aktivního listu
    Set rngBunka = Nothing

    'True
    blnRes = rngBunka Is Nothing


    'Allen Browne:
    'datový typ Variant/Empty
    Dim varPromenna As Variant
   
    'nelze
    'x = varPromenna Is Nothing
   
    'dojde k přetypování na Variant/Object
    Set varPromenna = Nothing
   
    'True
    x = varPromenna Is Nothing

End Sub

Missing

  • ve VBA funkce IsMissing ověřuje, zda-li byl proceduře (funkci) předán argument (parametr musí být typu Variant, jinak budeme nuceni testovat výchozí hodnotu daného datového typu)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Sub TestMissing()

    Call VlastniFunkce1

    Call VlastniFunkce2
    Call VlastniFunkce2("")

End Sub

Function VlastniFunkce1(Optional varPromenna As Variant)

    'při volání Call VlastniFunkce
    'je proměnná varPromenna typu Variant/Error
    'a obsahuje hodnotu Missing
   
    Dim blnRes As Boolean

    'testovat na hodnotu Missing
    'lze jen proměnnu typu Variant
    blnRes = IsMissing(varPromenna)
   
    'nebo
    blnRes = IsError(varPromenna)

End Function

Function VlastniFunkce2(Optional varPromenna As String)

    'při volání Call VlastniFunkce2
    'je proměnná varPromenna typu String
    'a obsahuje prázdný řetězec coby výchozí hodnotu
   
    Dim blnRes As Boolean

    'nelze testovat na Missing
    'blnRes = IsMissing(varPromenna)
   
    'True
    blnRes = varPromenna = vbNullString

End Function

Prázdný řetězec (null string, zero-length string, empty string)
http://en.wikipedia.org/wiki/Empty_string

  • řetězec nulové délky, datový typ String neobsahující žádný znak
  • nemá zastoupení v ASCII tabulce
  • je-li ve VBA (nebo na listu) vyjadřován dvojicí uvozovek jdoucích bezprostředně za sebou (tj. „“, zero-length string, empty string), pak v paměti využívá 6 bitů a ukazatel na řetězec v paměti StrPtr(„“) = číslo
  • ve VBA konstanta vbNullString (null string, null pointer, rychlejší při porovnávání než „“), nezabírá v paměti místo, ukazatel na řetězec v paměti StrPtr(vbNullString) = 0
  • i když prázdná buňka obsahuje ve své vlastnosti Text prázdný řetězec, funkce listu JE.TEXT u ní narozdíl od skutečně obsaženého prázdného řetězce vrací NEPRAVDA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Sub TestPrazdnyRetezec()

    Dim a, b

    a = ""
    b = vbNullString
   
    'rozlišení "" a vbNullString
   
    'číslo...
    x = StrPtr(a)

    '0 (datový typ Long)
    x = StrPtr(b)

    'test na prázdný řetězec
   
    'True
    x = a = ""
   
    'lépe
    'True
    x = a = vbNullString
   
    'nejlépe
    'True
    x = Len(a) = 0

End Sub

Co je to ta inicializace?
Inicializace představuje explicitní přiřazení počáteční hodnoty do (deklarované) proměnné.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Sub PrikladDeklaraceInicializace()

    'VBA

    'deklarace proměnné s názvem intCislo datového typu
    'Integer, tj. celé číslo v rozsahu -32 768 až 32 767
    'vyžadující 2 bajty v paměti
    Dim intCislo As Integer
   
    'pozn. přidělování paměťového prostoru proměnným
    'se říká alokace paměti
   
    'již v tuto chvíli proměnná intCislo obsahuje nepřímo
    'definovanou (implicitní) hodnotu, což je pro datový typ
    'Integer nula

    'inicializace, tj. přiřazení počáteční hodnoty přímo
    '(explicitně)
    intCislo = 5

    'deklaraci a inicializaci současně lze ve VBA provést
    'pouze u konstant nebo volitelných parametrů procedur (funkcí)
   
    'konstanta
    Const dblPi As Double = 3.14159

    'VB.NET

    'deklaraci i inicializaci lze i u proměných
    'provádět současně
    'Dim intCislo As Integer = 5

End Sub

V souladu s teorií je tedy za tu pravou inicializaci považováno přiřazení intCislo = 5. Nicméně podle mého názoru prvotní inicializaci (nastavení výchozích hodnot) u jednoduchých datových typů provádí Excel už v rámci „továrního nastavení“. tj. bezprostředně po deklaraci. U objektových proměnných je inicializace čistě na nás (a stejně tak inicializace třídy).

A jaké jsou výchozí hodnoty pro jednoduché datové typy?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Sub VychoziHodnotyDatovychTypu()

    'hodnota (datový typ/podtyp)
   
    'Empty (Variant/Empty)
    Dim a 'totéž jako As Variant

    '0 (Integer)
    Dim b As Integer

    '0 (Double)
    Dim c As Double

    'vbNullString, konstanta pro prázdný řetězec (String)
    Dim d As String
   
    'Chr(0), znak pro prázdný řetězec (String)
    Dim e As String * 255

    'Nothing (Object)
    Dim f As Object
   
    'False (Boolean)
    Dim g As Boolean
   
    '? (Variant(), tj. pole budoucích hodnot typu Variant)
    Dim h()

    '? (String(), tj. pole budoucích hodnot typu String)
    Dim i() As String

End Sub

Tip 1
Je možné snadno převést Null, Empty a prázdný řetězec na nulu? Ano.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Sub NulaZNiceho()

    Dim a, b, c, d

    a = Null
    b = vbNullString
    c = Empty

    'univerzální převod, výsledkem 0
    d = Val("" & a)
    e = Val("" & b)
    f = Val("" & c)

End Sub

Tip 2
Je možné snadno testovat, zda-li je prázdné pole? Ano.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Sub TestyPole()

    Dim Pole1(1 To 3)
    Dim Pole2()

    'True
    boolPole1JePrazdne = Len(Join(Pole1, "")) = 0
   
    Pole1(2) = "Liberec"
    Pole1(3) = 256
   
    'False
    boolPole1JePrazdne = Len(Join(Pole1, "")) = 0

    'True
    boolPole2JePrazdne = (Not Pole2) = True
   
    'Array nebo ReDim
    Pole2 = Array(vbNullString, vbNullString)
   
    'False
    boolPole2JePrazdne = (Not Pole2) = True

End Sub

Je to vše?
Bohužel, ani náhodou. Hlavní „války o nic“ se odehrávají na listu Excelu. Do bitev vstupuje skrytí buňky přímo či filtrem, formát buňky pro zneviditelnění hodnoty (vynechání sekce po sobě jdoucími středníky), skrývání nul a další lahůdky související s XML (viz třeba článek Záhada zmrazené buňky).

Prázdná buňka
Její definici jsem čas od času nucen sám přehodnotit v souvislosti s novými poznatky. V souladu s tím, co bylo napsáno výše, se obsah skutečně prázdné buňky chová jako Variant/Empty. Podle kontextu je brána jako nula (běžný výsledek prostého odkazu na buňku), prázdný řetězec nebo NEPRAVDA. Přesto vás výsledky některých funkcí listu jistě zaskočí.

Prázdná buňka a funkce listu - 1. část
Prázdná buňka a funkce listu – 1. část
Prázdná buňka a funkce listu - 2. část
Prázdná buňka a funkce listu – 2. část
Prázdná buňka a funkce listu - 3. část
Prázdná buňka a funkce listu – 3. část

U prázdné buňky převažuje numerické chování nad textovým. To je bohužel nepříjemné. Z odkazu ve vzorci obdržíme nulu, čímž Excel smaže rozdíl mezi „mít nulu“ a „nemít nic“. To v praxi znamená nerozlišovat mezi „nemít založen v bance účet“ a „nemít na existujícím účtu ani korunu“. Nebo – a to je horší – neprovádět měření versus naměřit nulovou odchylku. Do třetice příklad vypůjčený spíš z oblasti databází – odpojený elektroměr pana Kropáčka (potřebujeme přitom zachovat záznam o tom, že byl klientem naší společnosti), a paní Šebestová, která za daný měsíc neodebrala elektřinu, protože je momentálně s přítelem Machem v zahraničí.