zplCore.comzplCore.com

Dokumentation · Label-Modell

Ausdrücke
Funktionen, Formate, Kulturen.

Ein Ausdruck berechnet den Text eines Etikett-Elements aus dem Datensatz: Format([price], "C", [culture]), If([qty] > 10, "BULK", "SINGLE"), GS1("01", [gtin], "10", [lot]). Diese Seite beschreibt jede Funktion mit Parametern, Ergebnissen und Fehlern, dazu Operatoren, Umwandlungen, Kulturen und Formate – jedes Beispiel darauf wird von einem Test gegen die echte Engine ausgewertet.

Expression-Builder öffnen Funktionsreferenz

01Wo Ausdrücke verwendet werden

Jedes Element des Label-Modells hat die Eigenschaft Expression (JSON "expression"): Textelemente, Barcodes (Code) und RFID-Elemente (Data). Ist ein Ausdruck gesetzt, hat er Vorrang vor Text/Code und vor DataField. Das Ergebnis wird mit der Engine-Kultur in Text umgewandelt und dann gedruckt; Platzhalter {t:key} im Ergebnis werden wie in festen Texten übersetzt.

{ "type": "text", "x": 4, "y": 4, "expression": "Upper([name]) + \", \" + [customer.city]" }
{ "type": "barcode", "x": 4, "y": 20, "symbology": "Gs1_128", "expression": "GS1(\"01\", [gtin], \"10\", [lot])" }

Die Engine ist ZplCore.Labels.ExpressionEngine; jedes Label hat eine (label.Expressions) für eigene Funktionen, Variablen und die Kultur. Ausdrücke werden beim Binden des Etiketts je Datensatz ausgewertet (label.For<T>(), JSON-Datensätze, DataRow …) und bei label.ToZpl() ohne Daten einmal.

Zu den Beispielen. Sofern eine Tabelle nichts anderes angibt, lesen die Beispiele den Beispieldatensatz unten, laufen im ersten Datensatz eines Auftrags mit 3 Datensätzen auf einem Etikett mit 100 × 50 mm, verwenden die Standard-Engine-Kultur (invariant), und Now() ist der 22. Oktober 2026, 14:30:05. Die Spalte „Ergebnis“ zeigt den gedruckten Text. Ein Klick auf einen Ausdruck öffnet ihn im Expression-Builder.
{
  "price": 1234.5,
  "oldPrice": 1499,
  "culture": "de-DE",
  "name": "Müller",
  "first": "Anna",
  "last": "Schmidt",
  "sku": "ab-123",
  "qty": 3,
  "weight": 0.4567,
  "date": "2026-10-22",
  "deDate": "22.10.2026",
  "gtin": "09521234543213",
  "lot": "LOT42",
  "serial": "42",
  "textPrice": "19.99",
  "textOld": "9.99",
  "empty": "",
  "nothing": null,
  "inStock": true,
  "Preis [EUR]": 4.5,
  "Preis.netto": 3.1,
  "customer": { "name": "ACME GmbH", "city": "Graz", "zip": "8010" },
  "items": [ { "name": "Bolt" }, { "name": "Nut" } ]
}

02Schnellstart: ein Preisschild in mehreren Kulturen

Zwei Textelemente: der alte Preis, durchgestrichen, nur wenn er höher ist als der aktuelle Preis, und der aktuelle Preis als Währung. Die Kultur kommt aus dem Datensatz ([culture]), sodass ein einziges Etikett deutsche, US- oder japanische Preise druckt:

{ "type": "text", "expression": "If([oldPrice] > [price], \"instead of \" + Format([oldPrice], \"C\", [culture]), \"\")", "strikeout": true },
{ "type": "text", "expression": "Format([price], \"C\", [culture])", "fontSize": 22, "bold": true }
AusdruckDatensatzErgebnis
If([oldPrice] > [price], "instead of " + Format([oldPrice], "C", [culture]), "")Beispiel (de-DE)instead of 1.499,00 €
Format([price], "C", [culture])Beispiel (de-DE)1.234,50 €
If([oldPrice] > [price], "instead of " + Format([oldPrice], "C", [culture]), "")en-USinstead of $1,499.00
Format([price], "C", [culture])en-US$1,234.50
Format([price], "C", [culture])ja-JP¥1,234
If([oldPrice] > [price], "instead of " + Format([oldPrice], "C", [culture]), "")alter Preis niedriger(leer)
Format([price], "C", [culture])kein Feld culture¤1,234.50
  • Das Kultur-Argument ist ein Kulturname wie "de-DE", als Literal geschrieben oder aus einem Feld gelesen. Fehlt es oder ist es leer → die Engine-Kultur (Standard: invariant, Währungszeichen ¤). Siehe Kulturen.
  • Der Vergleich [oldPrice] > [price] ist numerisch – auch wenn Preise als Text kommen (CSV, JSON-Strings): Zwei Texte, die Zahlen sind, werden als Zahlen verglichen. Siehe Typen.
  • Ein leeres Ergebnis druckt nichts; das durchgestrichene Element bleibt dann einfach leer.

03Syntax

ElementSchreibweiseHinweise
Feld[price], [customer.city], [items[0].name], [Preis [EUR]]Wert des Datensatzes (oder eines anderen Elements, siehe Felder). Klammern innerhalb eines Namens werden verschachtelt. Ohne exakten Treffer wird Groß-/Kleinschreibung ignoriert.
Name ohne Klammernprice, LABEL_NUMBER, SHIFTBuchstaben, Ziffern, _. Wird zuerst als Variable, dann als Feld gesucht.
Zahl42, 1.5, .5Ziffern mit . als Dezimaltrennzeichen, immer invariant. Kein Exponent (1e3 ist ein Fehler), kein Tausendertrennzeichen; negative Zahlen mit unärem -.
Text"instead of ", "He said ""hi"""Doppelte Anführungszeichen, am Ende geschlossen (ein offener Text ist ein Fehler); ein Anführungszeichen im Text wird verdoppelt. Keine Backslash-Escapes. Im Label-JSON werden die Anführungszeichen noch einmal maskiert: "expression": "Upper(\"x\")".
Boolescher Werttrue, falseBeliebige Schreibweise. Gedruckt als True/False.
FunktionsaufrufFormat([price], "C")Funktionsnamen ignorieren Groß-/Kleinschreibung. Argumente sind Ausdrücke, getrennt durch ,.
Klammern([a] + [b]) * 2Gruppierung.
Member-ZugriffMath.Max(1, [qty])Nur für Typen, die mit AddTypeReference (C#) registriert sind, siehe C#-API.
AusdruckErgebnis
"He said ""hi"""He said "hi"
.5 + 11.5
0077
price * 22469
[PRICE]1234.5
TRUETrue
1e3Unexpected 'e3'

04Operatoren & Rangfolge

Von niedrigster zu höchster Rangfolge; Operatoren derselben Stufe werden von links nach rechts ausgewertet.

StufeOperatorenBedeutung
1or ||Logisches Oder (beide Seiten werden ausgewertet)
2and &&Logisches Und (beide Seiten werden ausgewertet)
3= == <> != < <= > >=Vergleich: numerisch, wenn eine Seite eine Zahl ist oder beide Seiten Texte sind, die Zahlen sind, sonst als Text ohne Beachtung der Groß-/Kleinschreibung
4+ - &+ addiert zwei Zahlen und verbindet alles andere als Text; & verbindet immer als Text; - subtrahiert
5* / %Multiplikation, Division, Rest (immer numerisch)
6- not !Unäres Minus, logisches Nicht
7( ), Aufrufe, .Gruppierung, Funktionsaufrufe, Member-Zugriff
AusdruckErgebnisWarum
1 + 2 * 37* vor +
(1 + 2) * 39Gruppierung
10 / 42.5Division ist nie eine Ganzzahldivision
10 % 31Rest
-7 % 3-1Vorzeichen der linken Seite
10 / 0Infinitykein Fehler; mit If absichern
2 + "3"23Text auf einer Seite → verbunden
"2" * "3"6* wandelt immer in Zahlen um
"2" - "3"-1- wandelt immer in Zahlen um
1 + 2 & 333gleiche Stufe, von links nach rechts: (1 + 2) & 3
[qty] & " pcs"3 pcs& verbindet
"a" = "A"TrueTextvergleich ignoriert Groß-/Kleinschreibung
"01" = 1TrueZahl auf einer Seite → numerisch
"01" = "1"Truebeide Texte sind Zahlen → numerisch
"10" < "9"Falsebeide Texte sind Zahlen → 10 < 9
"a10" < "a9"TrueTextvergleich, Zeichen für Zeichen
3 > 2 > 1False(3 > 2) = True, dann True > 1 → 1 > 1
[qty] > 2 and [inStock]True
not [qty] = 3Falsenot bindet zuerst: (not 3) = 3
not ([qty] = 3)Falsemit Klammern
[qty] <> 3 || [qty] != 4True

05Typen & Umwandlung

Werte sind Zahlen (double), Text, boolesche Werte, Datumswerte (DateTime) oder leer (null). Ganzzahl- und Dezimalwerte aus Datensätzen (C# int, long, decimal, JSON-Zahlen) werden zu Zahlen; alles andere behält seinen Typ. Umgewandelt wird dort, wo ein Operator oder eine Funktion einen anderen Typ braucht:

UmwandlungRegel
→ Textleer → ""; boolesche Werte → True/False; Zahlen und Datumswerte mit der Engine-Kultur (invariant: 1234.5, 10/22/2026 14:30:05).
→ Zahlleer → 0; true → 1, false → 0; Text wird mit der Engine-Kultur gelesen, dann invariant, sonst 0 (NumberStyles.Float: Vorzeichen, Dezimaltrennzeichen, Exponent – keine Tausendertrennzeichen).
→ boolescher Wertleer → false; Text → true, außer "", "0" oder "false" (beliebige Schreibweise); Zahlen → true, außer 0.
→ Datumein Datum bleibt; Text wird mit der Engine-Kultur gelesen, dann invariant, sonst 0001-01-01. Für feste Formate ToDate(text, format) verwenden.

+ addiert nur, wenn beide Seiten Zahlen sind. Eine Zahl aus einem Textfeld ist Text: [textPrice] + 1 verbindet. Vergleiche sind numerisch, wenn eine Seite eine Zahl ist oder beide Seiten Texte sind, die Zahlen sind (gelesen mit der Engine-Kultur, dann invariant); anderer Text wird als Text verglichen. Zum Rechnen mit Num() (oder ToNumber(text, culture)) umwandeln:

AusdruckErgebnisWarum
[qty] + 14JSON-Zahl
[textPrice] + 119.991Text + Zahl → verbunden
Num([textPrice]) + 120.99zuerst umgewandelt
[textOld] > [textPrice]Falsebeides Zahltexte: 9,99 > 19,99
Num([textOld]) > Num([textPrice])False9.99 > 19.99 als Zahlen
[textPrice] * 239.98* wandelt um
true + 1True1ein boolescher Wert ist für + keine Zahl
1 / 30.3333333333333333volle Genauigkeit; mit Round oder Format runden
0.1 + 0.20.30000000000000004binäre Gleitkommazahl
Format(0.1 + 0.2, "0.00")0.30für den Druck formatieren
Today()10/22/2026 00:00:00Datum → Text (invariant)

Mit der Engine-Kultur de-DE (C#: label.Expressions.Culture) folgen dieselben Umwandlungen deutschen Konventionen:

Ausdruck (Engine-Kultur de-DE)Ergebnis
[price]1234,5
[price] + " EUR"1234,5 EUR
Num("19,99") * 239,98
Num("19.99") * 239,98
Format(ToDate([deDate]), "yyyy-MM-dd")2026-10-22
Today()22.10.2026 00:00:00

06Leere & fehlende Werte

Ein Feld, das fehlt, JSON-null oder C#-null ist, ist leer. Ohne Daten (label.ToZpl()) ist jedes Feld leer. Leere Werte lösen nie einen Fehler aus: Sie drucken als "", zählen als 0 und als false.

AusdruckErgebnisWarum
[missing](leer)unbekanntes Feld
Upper([nothing]) & "|"|leerer Text
[nothing] * 20leer → 0
[missing] + 11leer ist keine Zahl → verbunden: "" + "1"
[missing] + 1 + 111"1" + 1 → wieder verbunden
Num([missing]) + 1 + 12zuerst umwandeln
If([nothing], "yes", "no")noleer → false
IsEmpty([empty])True""
IsEmpty([nothing])Truenull
IsEmpty(" ")Falseein Leerzeichen ist Text
Coalesce([empty], [nothing], "n/a")n/aerster nicht leerer Wert
If(IsEmpty([lot]), "", "LOT " + [lot])LOT LOT42Text nur, wenn ein Wert vorhanden ist
Format([nothing], "C", "de-DE")(leer)nichts zu formatieren

07Felder & Bindung

[name] liest einen Wert des aktuellen Datensatzes. Datensätze können C#-Objekte (Properties und Felder), Dictionaries, ExpandoObject, JsonElement/JsonNode, DataRow oder LiteDB-Dokumente sein; LabelBinding.Map("name", r => …) fügt berechnete Felder hinzu. Die Suche:

  1. Ein Name mit . oder [n] ist ein Pfad: [customer.city], [items[0].name]. Eine Spalte, deren Name genau dieser Text ist, hat Vorrang vor dem Pfad (importierte Tabellen haben oft Spalten wie Preis.netto).
  2. Zuerst der exakte Name, dann ohne Beachtung der Groß-/Kleinschreibung.
  3. Namen anderer Elemente: [Items.Total] oder [Items.Total.Text] ist der gedruckte Text des Elements namens Total – auch wenn es später auf dem Etikett kommt (Zirkelbezüge ergeben ""). Ein bloßes [Total] findet ein Element erst, nachdem es gedruckt wurde, und nur, wenn kein Feld des Datensatzes so heißt.
AusdruckErgebnis
[customer.city]Graz
[items[1].name]Nut
[items[5].name](leer)
[Preis [EUR]] * 29
[Preis.netto]3.1
[CUSTOMER.CITY]Graz
[customer.zip] + " " + [customer.city]8010 Graz
[inStock]True
var label = new Label(LabelUnit.Mm, 100, 50)
    .Add(new TextItem { Name = "Net", Y = 4, Expression = "Format([price] / 1.2, \"0.00\")" })
    .Add(new TextItem { Y = 12, Expression = "\"net \" + [Items.Net] + \" / gross \" + Format([price], \"0.00\")" });
// mit { price = 12 }: "net 10.00 / gross 12.00"

08Auftragsvariablen

Variablen werden ohne Klammern geschrieben (mit Klammern funktionieren nur die mit ✓ markierten Bindungsvariablen).

VariableWert[…]
LABEL_INDEXNullbasierte Nummer des Etiketts (Datensatzes) im Auftrag–
LABEL_NUMBEREinsbasiert: LABEL_INDEX + 1–
REPEAT_INDEXNullbasierter Elementindex innerhalb eines RepeaterItem–
RECORD_INDEXNullbasierter Datensatzindex (Bindungen)✓
PAGE_NUMBEREinsbasierte Datensatznummer (Bindungen)✓
TOTAL_PAGESAnzahl der Datensätze, wenn bekannt (Collections, WithRecordCount), sonst leer✓
LABEL_WIDTH, LABEL_HEIGHTEtikettengröße in Etiketteneinheiten (Bindungen)✓
eigene, z. B. SHIFTlabel.Expressions.Variables["SHIFT"] = "B" oder SetCustomVariable–

Die Namen sind nicht reserviert: Ein Feld des Datensatzes namens PAGE_NUMBER (oder einer der anderen Bindungsvariablen) hat Vorrang vor der Variablen. LABEL_INDEX, LABEL_NUMBER und REPEAT_INDEX haben ohne Klammern geschrieben Vorrang vor gleichnamigen Feldern. Ohne Bindung (label.ToZpl()) sind die Bindungsvariablen leer.

AusdruckErgebnis
"Etikett " + LABEL_NUMBEREtikett 1
"Seite " + PAGE_NUMBER + " von " + TOTAL_PAGESSeite 1 von 3
RECORD_INDEX0
[LABEL_WIDTH] + " x " + LABEL_HEIGHT + " mm"100 x 50 mm
[LABEL_NUMBER](leer)
"Seite " + PAGE_NUMBERSeite A-7

09Kulturen

Eine Kultur bestimmt Dezimal- und Tausendertrennzeichen, Währung, Prozentzeichen, Datumsreihenfolge, Monats- und Tagesnamen – und bei manchen Kulturen sogar den Kalender. zplCore verwendet .NET-Kulturen (ICU-Daten des Betriebssystems). Sie wird an zwei Stellen festgelegt:

WoGilt fürStandard
Kultur-Argument von Format/ToString (3.), ToNumber (2.), IsNumeric (2.), ToDate (3.)nur diesen Aufrufdie Engine-Kultur
Engine-Kultur label.Expressions.Culture (C#) oder engine.Culturejede Umwandlung des Etiketts: Zahlen und Datumswerte als Text, Lesen von Zahlen und Datumswerten, Upper/Lower, Format ohne KulturCultureInfo.InvariantCulture
  • Der Standard ist invariant, damit sich Etiketten nie mit den Regionaleinstellungen des Servers ändern: 1234.5, 10/22/2026, Währungszeichen ¤.
  • Label-JSON hat keine Engine-Kultur (Label.Expressions wird nicht serialisiert). In JSON-Vorlagen die Kultur als Argument übergeben – als Literal "de-DE" oder aus dem Datensatz [culture]. Label.Culture ist etwas anderes: Es wählt die Sprache der Übersetzungen {t:key}.
  • Das Argument ist ein Kulturname: "de-DE", "en-US", "fr-CH", eine neutrale Sprache wie "de" oder "". Ein Wert, der kein Text ist (Zahl, leeres Feld), oder leerer Text bedeutet die Engine-Kultur.
  • Unbekannte Namen lösen FormatException: Unknown culture '…' aus: Angenommen werden nur Kulturen, die .NET kennt (in den ICU-Daten vordefiniert) – "!!", "xx-YY" oder "foo" schlagen fehl.
  • Datengebundene Elemente ohne Ausdruck verwenden stattdessen DataFieldFormat und TextItem.CultureName (ohne Kultur: invariant mit einem Format); Ausdrücke lesen CultureName nicht. Der Standardkalender und die normalen Leerzeichen (unten) gelten auch dort.
AusdruckErgebnisKultur aus
Format([price], "C", "de-DE")1.234,50 €Literal
Format([price], "C", [culture])1.234,50 €Feld
Format([price], "C", If([customer.city] = "Graz", "de-AT", "en-US"))€ 1.234,50berechnet
Format([price], "C")¤1,234.50Engine (invariant)
Format([price], "C", "")¤1,234.50Engine
Format([price], "C", [missing])¤1,234.50Engine
Format([price], "N2", "de")1.234,50neutrale Kultur
Format([price], "C", "!!")Unknown culture '!!'fehlerhaft
Format([price], "C", "xx-YY")Unknown culture 'xx-YY'unbekannt
Upper("istanbul")ISTANBULEngine (invariant)

Die Engine-Kultur ändert die Umwandlungen ohne Argumente (hier tr-TR, wo der Großbuchstabe von i İ ist):

Ausdruck (Engine-Kultur tr-TR)Ergebnis
Upper("istanbul")İSTANBUL
Format([price], "C")₺1.234,50
Format([price], "C", "en-US")$1,234.50
var label = Label.FromJson(json);                         // JSON: keine Engine-Kultur
label.Expressions.Culture = CultureInfo.GetCultureInfo("de-DE");   // C#: für das ganze Etikett
// Format([price], "C") → "1.234,50 €", [price] + " EUR" → "1234,5 EUR"
// Format([price], "C", "en-US") → "$1,234.50" (das Argument hat Vorrang)

Ergebnisse je Kultur

Dieselben Werte in gängigen Kulturen. Der Engine druckt sie unter Windows, Linux und macOS gleich: Sonder-Leerzeichen werden zu normalen Leerzeichen – die geschützten und schmalen geschützten Leerzeichen der Tausendergruppen von fr-FR, pl-PL oder sv-SE und in Uhrzeiten wie 2:30 PM (U+00A0, U+202F, U+2000–U+200A, U+205F), die ICU-Versionen unterschiedlich setzen und Druckerschriften oft nicht drucken können – und Datumswerte verwenden den Standardkalender der Kultur (unten). Andere Zeichen stammen weiter aus den ICU-Daten des Betriebssystems, z. B. der Apostroph von de-CH (’ oder ') und die Richtungszeichen arabischer Texte; die Tests vergleichen diese normalisiert.

AusdruckErgebnis
Format(1234.5, "C", "de-DE")1.234,50 €
Format(1234.5, "C", "de-AT")€ 1.234,50
Format(1234.5, "C", "de-CH")CHF 1’234.50
Format(1234.5, "C", "en-US")$1,234.50
Format(1234.5, "C", "en-GB")£1,234.50
Format(1234.5, "C", "fr-FR")1 234,50 €
Format(1234.5, "C", "fr-CH")1 234.50 CHF
Format(1234.5, "C", "it-IT")1.234,50 €
Format(1234.5, "C", "es-ES")1.234,50 €
Format(1234.5, "C", "nl-NL")€ 1.234,50
Format(1234.5, "C", "pl-PL")1 234,50 zł
Format(1234.5, "C", "sv-SE")1 234,50 kr
Format(1234.5, "C", "ja-JP")¥1,234
Format(1234.5, "C", "zh-CN")¥1,234.50
Format(1234.5, "C", "ar-SA")1٬234٫50 ر.س.‏
Format(1234.5, "C", "ar-AE")1,234.50 د.إ.‏
Ausdruckde-DEen-USen-GBfr-FRfr-CHja-JPar-SA
Format(1234.5, "N2", c) 1.234,50 1,234.50 1,234.50 1 234,50 1 234,50 1,234.50 1٬234٫50
Format(0.125, "P1", c) 12,5 % 12.5% 12.5% 12,5 % 12,5% 12.5% 12٫5٪؜
Format(1234.5, "#,##0.00", c) 1.234,50 1,234.50 1,234.50 1 234,50 1 234,50 1,234.50 1٬234٫50
Format(ToDate([date]), "d", c) 22.10.2026 10/22/2026 22/10/2026 22/10/2026 22.10.2026 2026/10/22 11/05/1448
Format(ToDate([date]), "D", c) Donnerstag, 22. Oktober 2026 Thursday, October 22, 2026 Thursday, 22 October 2026 jeudi 22 octobre 2026 jeudi, 22 octobre 2026 2026年10月22日木曜日 جمادى الأولى
Kalender. Jede Kultur formatiert und liest Datumswerte in ihrem Standardkalender aus einer festen Tabelle (ExpressionEngine.StandardCalendar), auf jedem Betriebssystem gleich: ar-SA islamischer Umm-al-Qura-Kalender (22. Okt. 2026 = 11. Dschumada l-ula 1448; die letzte Spalte oben zeigt das Muster dd/MM/yyyy und den Monatsnamen), th/th-TH thailändisch-buddhistisch (Jahr 2569), persisch für fa, fa-IR, fa-AF, ps, ps-AF, ckb-IR, lrc, mzn und uz-Arab (Jahr 1405); alle anderen Kulturen gregorianisch. Ohne die Tabelle hing das Ergebnis vom Server ab: Linux formatierte ar-SA gregorianisch, Windows im Umm-al-Qura-Kalender. Für gregorianische Datumswerte mit arabischen Texten z. B. ar-AE oder ar-EG verwenden oder ein festes Muster mit invarianter Kultur: Format(ToDate([date]), "dd.MM.yyyy").
AusdruckErgebnis
Format(ToDate([date]), "d", "th-TH")22/10/2569
Format(ToDate([date]), "yyyy/MM/dd", "fa-IR")1405/07/30
Format(ToDate([date]), "d", "ar-AE")22‏/10‏/2026
Format(1234567.891, "N", "en-IN")12,34,567.891
Format(1234567.891, "N", "de-CH")1’234’567.891

10Zahlenformate

Das 2. Argument von Format(value, format, culture?) ist ein .NET-Formatstring. Für Zahlen:

FormatBedeutungGenauigkeit
C, C0…C99Währung der Kultur (Zeichen, Position, Nachkommastellen)Nachkommastellen; Standard aus der Kultur
N, N2Zahl mit TausendertrennzeichenNachkommastellen; Standard aus der Kultur (meist 2 oder 3)
F, F2Festkomma, ohne TausendertrennzeichenNachkommastellen
P, P1Prozent: Wert × 100 mit dem Prozentzeichen der KulturNachkommastellen
E, E2Exponentialdarstellung (4.57E-001)Nachkommastellen
G, RAllgemein / Round-Trip (kürzester exakter Text)signifikante Stellen
D, D5, X, X4Dezimalziffern mit führenden Nullen / hexadezimal – für ganze Zahlen; eine Zahl mit Nachkommastellen löst einen Fehler aus.Mindeststellen
Benutzerdefiniert: 0 # . , % ; 'text'0 Ziffer oder Null, # Ziffer, falls vorhanden, . Dezimaltrennzeichen, , Tausendertrennzeichen (oder ×1000 am Ende), % Prozent, ; Abschnitte positiv;negativ;null, Text in Anführungszeichen wörtlichwie geschrieben

Rundung: Standardformate mit weniger Nachkommastellen als der Wert (N0, F0, C0, P0 …) runden eine exakte Hälfte zur geraden Ziffer – 1234.5 → 1234, 2.5 → 2, 3.5 → 4. Benutzerdefinierte Formate ("0", "#,##0") und Round() runden die Hälfte von null weg (12.5 → 13). Preise zuerst runden: Format(Round([price]), "C0", …).

Trennzeichen in einem benutzerdefinierten Format sind Platzhalter: . druckt das Dezimaltrennzeichen der Kultur, , ihr Tausendertrennzeichen. Einheitentexte in einfache Anführungszeichen setzen ("0.00 'kg'"): Buchstaben wie E würden sonst als Formatzeichen gelesen. Doppelte Anführungszeichen würden den Text des Ausdrucks beenden.

AusdruckErgebnis
Format([price], "N2", "en-US")1,234.50
Format([price], "N0", "de-DE")1.234
Format([price], "N", "de-DE")1.234,500
Format([price], "F", "de-DE")1234,500
Format([price], "F0")1234
Format(2.5, "F0") + " " + Format(3.5, "F0")2 4
Format(12.5, "0") + " " + Format(13.5, "0")13 14
Format([price], "C0", "de-DE")1.234 €
Format(Round([price]), "C0", "de-DE")1.235 €
Format([price], "C3", "en-US")$1,234.500
Format(-1234.5, "C", "en-US")-$1,234.50
Format([weight], "P1", "en-US")45.7%
Format([weight], "P0", "de-DE")46 %
Format([weight], "E2", "en-US")4.57E-001
Format([price], "R")1234.5
Format([price], "0.00", "de-DE")1234,50
Format([price], "#,##0.00", "de-DE")1.234,50
Format([weight], "0.000 'kg'", "de-DE")0,457 kg
Format([weight] * 1000, "#,##0 'g'")457 g
Format([qty], "000")003
Format(-1234.5, "#,##0.00;(#,##0.00)", "en-US")(1,234.50)
Format(0, "#,##0.00;-#,##0.00;'free'")free
Format(1234567, "#,##0,'k'")1,235k
Format([qty], "D5")00003
Format(255, "X4")00FF
Format(2.5, "D3")Format specifier was invalid.
Format([price], "dd.MM.yyyy")dd1235MMyyyy

Zahlen als Text ("19.99" aus CSV oder einem JSON-String) werden wie Zahlen formatiert, wenn ein Format angegeben ist: Der Text wird mit der Engine-Kultur gelesen; Text, der keine Zahl ist, wird unverändert gedruckt.

AusdruckErgebnis
Format([textPrice], "C", "de-DE")19,99 €
Format("12.5", "0.00", "fr-FR")12,50
Format([sku], "0.00")ab-123
Format([textPrice])19.99

11Datumsformate

Format formatiert Datumswerte – Werte aus Now(), Today(), AddDays…, ToDate(…) oder DateTime-Feldern von C#-Datensätzen. Datumswerte in JSON oder CSV sind Text: Sie zuerst mit ToDate umwandeln, sonst druckt Format den Text unverändert.

FormatBedeutungde-DE / en-US
dKurzes Datum22.10.2026 / 10/22/2026
DLanges DatumDonnerstag, 22. Oktober 2026 / Thursday, October 22, 2026
t, TKurze / lange Uhrzeit14:30 / 2:30 PM
g, GDatum + Uhrzeit22.10.2026 14:30
o, u, sISO 8601 (kulturunabhängig)2026-10-22T14:30:05.0000000
dd d / ddd ddddTag 01–31 / 1–31, Tagesname kurz / langDo / Donnerstag
MM M / MMM MMMMMonat 01–12 / 1–12, Monatsname kurz / langOkt. / Oktober
yyyy yyJahr 4- / 2-stellig2026 / 26
HH hh mm ss ttStunde 00–23 / 01–12, Minute, Sekunde, AM/PM
'text', \xWörtlicher Text

.NET-Datumsformate kennen keine Kalenderwoche. / und : in einem Muster drucken die Datums- und Zeittrennzeichen der Kultur.

AusdruckErgebnis
Format(Today(), "dd.MM.yyyy")22.10.2026
Format(Now(), "yyyy-MM-dd HH:mm")2026-10-22 14:30
Format(Now(), "t", "en-US")2:30 PM
Format(Now(), "hh:mm tt", "en-US")02:30 PM
Format(Today(), "dddd, d. MMMM yyyy", "de-DE")Donnerstag, 22. Oktober 2026
Format(Today(), "MMM yyyy", "en-US")Oct 2026
Format(Today(), "ddd", "fr-FR")jeu.
Format(Today(), "yyMMdd")261022
Format(Today(), "o")2026-10-22T00:00:00.0000000
Format(Today(), "dd/MM/yyyy")22/10/2026
Format(Today(), "dd/MM/yyyy", "de-DE")22.10.2026
Format(Today(), "'KW' ww")KW ww
Format([date], "dd.MM.yyyy")2026-10-22
Format(ToDate([date]), "dd.MM.yyyy")22.10.2026

12Funktionsreferenz

Alle 47 eingebauten Funktionen. Namen ignorieren Groß-/Kleinschreibung. Fehlende Argumente sind leer (null); zusätzliche Argumente werden ignoriert, sofern nicht anders angegeben. Argumente werden wie unter Typen beschrieben umgewandelt: „Text“-Argumente durchlaufen die Text-Umwandlung, „Zahl“-Argumente die Zahlen-Umwandlung (keine Zahl → 0), Anzahlen werden auf ganze Zahlen abgeschnitten.

Text

Upper(text) · Lower(text)
Groß- / Kleinschreibung mit der Engine-Kultur. Gibt Text zurück.
Len(text)
Anzahl der UTF-16-Zeichen. Gibt eine Zahl zurück (leer → 0).
Left(text, n) · Right(text, n)
Die ersten / letzten n Zeichen; n wird auf 0…Länge begrenzt (nie ein Fehler).
Mid(text, start, n?)
1-basierter Start (1 = erstes Zeichen, Werte unter 1 zählen als 1), n Zeichen oder der Rest.
Substring(text, start, n?)
0-basierter Start (begrenzt), n Zeichen oder der Rest.
Trim(text, chars?) · TrimStart(text) · TrimEnd(text)
Entfernt Leerraum an beiden Enden / am Anfang / am Ende. Trim mit einem 2. Argument entfernt stattdessen diese Zeichen (jedes Zeichen des Textes ist eines, das entfernt wird).
Replace(text, find, with)
Ersetzt jedes Vorkommen (Groß-/Kleinschreibung wird beachtet). Ein leeres find gibt den Text unverändert zurück.
PadLeft(text, width, char?) · PadRight(text, width, char?)
Füllt auf width Zeichen mit dem ersten Zeichen von char auf (Standard: Leerzeichen). Längerer Text bleibt unverändert.
Contains(text, part) · StartsWith(text, part) · EndsWith(text, part)
True/false, ohne Beachtung der Groß-/Kleinschreibung.
IndexOf(text, part)
0-basierte Position von part ohne Beachtung der Groß-/Kleinschreibung, −1, wenn nicht vorhanden.
Concat(value, …)
Verbindet beliebig viele Werte als Text (leere Werte fügen nichts hinzu).
Repeat(text, n)
Der Text n-mal; n wird auf 0…10.000 begrenzt.
AusdruckErgebnis
Upper([name])MÜLLER
Lower("ÄÖÜ")äöü
Len([name])6
Left([name], 3)Mül
Left([name], 99)Müller
Right([name], 2)er
Mid([name], 2, 3)üll
Mid([name], 2)üller
Substring([name], 1, 3)üll
Trim(" x ") & "|"x|
Trim("--x--", "-")x
"|" & TrimStart(" x ") & "|"|x |
"|" & TrimEnd(" x ") & "|"| x|
Replace([name], "ü", "ue")Mueller
Replace([sku], "-", "")ab123
PadLeft([serial], 6, "0")000042
PadRight("42", 5, "*")42***
PadLeft("123456", 3, "0")123456
Contains([name], "MÜL")True
StartsWith([sku], "AB")True
EndsWith([name], "x")False
IndexOf([name], "L")2
IndexOf([name], "z")-1
Concat([first], " ", [last], [nothing])Anna Schmidt
Repeat("*", 5)*****
Left([first], 1) + ". " + Upper([last])A. SCHMIDT

Bedingungen

If(condition, then, else?)
Gibt then zurück, wenn die Bedingung wahr ist (siehe Umwandlung in boolesche Werte), sonst else (fehlt es → leer). Beide Zweige werden vor der Auswahl ausgewertet, ein Zweig darf also keinen Fehler auslösen (z. B. GS1 mit leerem Wert) – stattdessen die Argumente auswählen.
IsEmpty(value)
True für leere Werte und ""; " " und 0 sind nicht leer.
Coalesce(value, …)
Der erste Wert, der weder leer noch "" ist; leer, wenn es keinen gibt.
AusdruckErgebnis
If([qty] > 2, "BULK", "SINGLE")BULK
If([inStock], "in stock", "sold out")in stock
If([qty] > 5, "BULK")(leer)
If("0", "yes", "no")no
If("false", "yes", "no")no
If("abc", "yes", "no")yes
If([qty] = 1, "1 piece", [qty] + " pieces")3 pieces
If([weight] < 1, Format([weight] * 1000, "0 'g'"), Format([weight], "0.0 'kg'"))457 g
Coalesce([empty], [customer.name])ACME GmbH
Coalesce(0, "x")0
IsEmpty(0)False

Mathematik

Round(number, decimals?)
Rundet die Hälfte von null weg (2,5 → 3, −2,5 → −3) auf 0…15 Nachkommastellen (Standard 0; Werte außerhalb werden begrenzt, negative Stellen runden also auf ganze Zahlen). Es gilt binäre Gleitkommaarithmetik: Round(1.005, 2) ergibt 1.
Floor(number) · Ceiling(number) · Abs(number)
Abrunden / Aufrunden, Betrag.
Min(number, …) · Max(number, …)
Kleinstes / größtes der Argumente als Zahl; ohne Argumente 0.
AusdruckErgebnis
Round(2.5)3
Round(-2.5)-3
Round(2.345, 2)2.35
Round(1.005, 2)1
Round([price], -1)1235
Round([price] * 1.2, 2)1481.4
Floor(-2.7)-3
Ceiling([qty] / 2)2
Abs(-3)3
Max(3, "10", 2)10
Min([qty], 2)2
Min()0

Datum

Now() · Today()
Aktuelles Datum mit Uhrzeit / heute um 00:00 aus Expressions.Clock (Standard: die lokale Uhr). Die Uhr für Tests oder Nachdrucke mit dem ursprünglichen Datum setzen.
AddDays(date, days) · AddMonths(date, months) · AddYears(date, years)
Addiert (oder subtrahiert, negativ) Tage – Bruchteile erlaubt – oder ganze Monate / Jahre. Ein Datum als Text wird wie bei ToDate(text) umgewandelt. Das Monatsende bleibt gültig (31. Jan. + 1 Monat = 28./29. Feb.).
ToDate(text, format?, culture?)
Liest ein Datum. Mit format muss der Text exakt passen (DateTime.TryParseExact, Namen in culture); andernfalls – oder wenn er nicht passt – wird der Text mit der Engine-Kultur gelesen, dann invariant. Text, der kein Datum ist, ergibt 0001-01-01 (kein Fehler): bei Bedarf mit Format(…, "yyyy") = "0001" prüfen.
AusdruckErgebnis
Format(AddDays(Today(), 30), "dd.MM.yyyy")21.11.2026
Format(AddDays(Now(), -0.5), "dd.MM. HH:mm")22.10. 02:30
Format(AddMonths(ToDate([date]), 18), "MM/yyyy")04/2028
Format(AddMonths(ToDate("2027-01-31"), 1), "yyyy-MM-dd")2027-02-28
Format(AddYears([date], 2), "yyyy-MM-dd")2028-10-22
Format(ToDate([deDate], "dd.MM.yyyy"), "yyyy-MM-dd")2026-10-22
Format(ToDate("22. Oktober 2026", "d. MMMM yyyy", "de-DE"), "d")10/22/2026
Format(ToDate([deDate]), "yyyy-MM-dd")0001-01-01
Format(ToDate("10/22/2026"), "yyyy-MM-dd")2026-10-22
Format(ToDate("garbage"), "yyyy")0001

Umwandlung & Formatierung

Format(value, format?, culture?) · ToString(value, format?, culture?)
ToString ist dieselbe Funktion unter anderem Namen. Zahlen, Datumswerte und andere formatierbare Werte: value.ToString(format, culture) (siehe Zahlen- und Datumsformate). Text mit einem Format wird mit der Engine-Kultur als Zahl gelesen und formatiert; anderer Text, boolesche Werte und leere Werte werden unverändert in Text umgewandelt. Ohne Format: der Wert als Text in culture. Fehler: unbekannter Kulturname, ein Format, das der Wert ablehnt (D, X bei einer Zahl mit Nachkommastellen).
Str(value)
Wert als Text mit der Engine-Kultur.
Num(value)
Wert als Zahl mit der Engine-Kultur (dann invariant); keine Zahl → 0.
ToNumber(text, culture?)
Wie Num, der Text wird zuerst in culture gelesen. Akzeptiert Vorzeichen, ein Dezimaltrennzeichen und Exponent; mit Kultur-Argument auch die Tausendertrennzeichen dieser Kultur an ihren Stellen ("1.234,5" in de-DE → 1234.5, aber "12,5" in en-US ist keine Zahl). Ohne Kultur keine Tausendertrennzeichen. Keine Zahl → 0.
IsNumeric(value, culture?)
True für Zahlen und für Text, der sich in culture als Zahl lesen lässt (mit Kultur-Argument wie bei ToNumber samt Tausendertrennzeichen; Standard: Engine-Kultur); false für boolesche Werte, leere Werte und anderen Text.
AusdruckErgebnis
Format([price])1234.5
Format([price], "", "de-DE")1234,5
ToString([price], "0.0")1234.5
Format([inStock], "C")True
Str([qty]) + Str(1)31
Num("12.5") * 225
Num("12,5")0
ToNumber("12,5", "de-DE") * 225
ToNumber("1.234,5", "de-DE")1234.5
ToNumber("1,234.5", "en-US")1234.5
ToNumber("12,5", "en-US")0
ToNumber("1.234,5")0
ToNumber(Replace("1.234,5", ".", ""), "de-DE")1234.5
ToNumber("1e3")1000
IsNumeric([textPrice])True
IsNumeric("12,5")False
IsNumeric("12,5", "de-DE")True
IsNumeric("1.234,5", "de-DE")True
IsNumeric([sku])False
IsNumeric(true)False

Prüfziffern

Gs1CheckDigit(digits)
Gibt die Ziffern mit angehängter GS1-Mod-10-Prüfziffer zurück (GTIN, SSCC, GLN …). Die Eingabe wird nicht geprüft – nur Ziffern übergeben.
Mod10(digits) · Luhn(digits) · Mod11(digits) · Mod43(text)
Geben nur das Prüfzeichen zurück: GS1/UPC-Gewichtung 3-1, Luhn (Karten), Mod 11 mit Gewichten 2…7 (X für 10), Code 39 Mod 43. Fehler: für das Verfahren ungültige Zeichen.
VoicePickCode(gtin, lot, date?)
Der 4-stellige PTI-Voice-Pick-Code (CRC-16 aus GTIN + Charge [+ Datum als YYMMDD]); ein Datumswert wird als yyMMdd geschrieben.
AusdruckErgebnis
Gs1CheckDigit("400638133393")4006381333931
Gs1CheckDigit("0952123454321")09521234543213
Mod10("400638133393")1
Luhn("7992739871")3
Mod11("12345")5
Mod43("CODE39")W
VoicePickCode("10850510002011", "46587443HG234", "101026")1997
VoicePickCode("10850510002011", "46587443HG234")0862

GS1

GS1(ai1, value1, ai2, value2, …)
Baut aus Paaren den GS1-Element-String in Klammerschreibweise (01)…(10)…. AIs werden als Text geschrieben ("01", 2–4 Ziffern; Klammern werden entfernt). Jedes Paar wird gegen die GS1-Tabelle geprüft – bekannter AI, Länge, Zeichensatz, Prüfziffer, Datum, Pflicht- und Ausschlusskombinationen –, ein Fehler löst eine FormatException mit dem betroffenen AI aus, sodass nie ein falscher Code gedruckt wird. Als Expression eines GS1-128-Barcodes (Symbology.Gs1_128) verwenden: Die FNC1-Trenner nach Werten variabler Länge werden beim Schreiben des Barcodes eingefügt. Werte dürfen keine Klammern enthalten.
AusdruckErgebnis
GS1("01", [gtin], "10", [lot])(01)09521234543213(10)LOT42
GS1("01", [gtin], "17", Format(AddMonths(Today(), 14), "yyMMdd"), "10", [lot])(01)09521234543213(17)271222(10)LOT42
GS1("(01)", [gtin])(01)09521234543213
GS1("01", "09521234543214")GS1(): AI 01: Bad checksum
GS1("01", [gtin], "10", [empty])GS1(): AI 10 has no value
GS1(1, [gtin])GS1(): '1' is not an application identifier (2 to 4 digits, written as text, e.g. "01")
GS1("01")GS1() takes pairs of application identifier and value, e.g. GS1("01", [Gtin], "10", [Lot])
GS1("10", "A(B)")GS1(): the value of AI 10 contains a parenthesis, which GS1-128 printed with ^BC mode D removes from the data
"GTIN " + Mid(GS1("01", [gtin]), 5)GTIN 09521234543213
label.Add(new BarcodeItem
{
    X = 5, Y = 20, Symbology = Symbology.Gs1_128,
    Expression = "GS1(\"01\", [gtin], \"17\", Format(ToDate([expiry]), \"yyMMdd\"), \"10\", [lot])",
});

Mehr zu GS1-Barcodes: GS1 in der Dokumentation.

13C#-API

ExpressionEngine lässt sich eigenständig oder über label.Expressions verwenden:

using System.Globalization;
using ZplCore.Labels;

var engine = new ExpressionEngine
{
    Culture = CultureInfo.GetCultureInfo("de-DE"),          // Standard: InvariantCulture
    Clock = () => new DateTime(2026, 10, 22, 14, 30, 5),     // Now()/Today()
};
engine.Variables["VAT"] = 0.19;                                // eigene Variablen
engine.SetCustomFunction("Euro", a => ExpressionEngine.Num(a[0]).ToString("0.00", CultureInfo.InvariantCulture) + " EUR");

var record = new Dictionary<string, object?> { ["price"] = 12.5m };
object? value = engine.Evaluate("[price] * (1 + VAT)", f => record.GetValueOrDefault(f));   // 14.875 (double)
string text = engine.EvaluateToString("Euro([price])", f => record.GetValueOrDefault(f));   // "12.50 EUR"
string date = engine.EvaluateToString("Format(Today(), \"D\")");                             // "Donnerstag, 22. Oktober 2026"
MemberZweck
Evaluate(expression, fieldResolver?)Ergebnis als Wert (Zahl = double, Text, bool, DateTime, null). Der Resolver erhält jedes [name] (und unbekannte Namen ohne Klammern); ohne ihn sind Felder leer.
EvaluateToString(expression, fieldResolver?)Ergebnis als Text mit Culture – das, was ein Etikett druckt.
CultureEngine-Kultur (siehe Kulturen).
ClockUhr von Now()/Today().
Variables, SetCustomVariableEigene Variablen, Namen ignorieren Groß-/Kleinschreibung.
Functions, SetCustomFunctionAlle Funktionen (eingebaute lassen sich ersetzen): Func<object?[], object?> erhält die ausgewerteten Argumente.
AddTypeReference(type, alias?)Erlaubt Type.Member und Member auf Werten dieses Typs, z. B. Math.Max(1, [qty]), DateTime.Now.AddDays(3). Sonst ist nichts erreichbar.
Str, Num, Bool (statisch), ToText, ToNumDie Umwandlungen der Engine, für eigene Funktionen (statisch = invariant).

Threadsicherheit: Einmal konfiguriert, darf Evaluate auf vielen Threads laufen (Etikettenaufträge tun das). Das Konfigurieren (Variablen, Funktionen, Typreferenzen) ist nicht threadsicher. Eigene Funktionen, Typreferenzen und eine eigene Uhr lassen Aufträge standardmäßig sequenziell laufen, siehe parallele Erzeugung.

14Fehler

Ein ungültiger Ausdruck löst eine FormatException aus, wenn das Element erzeugt wird (ToZpl, Render, Bindungsaufträge) – das Etikett wird nicht mit falschem Text gedruckt. Die Meldungen sind englisch:

AusdruckMeldung
Foo(1)Unknown function Foo
Upper([name]Missing )
1 +Unexpected ''
1 2Unexpected '2'
"a" $ "b"Unexpected '$' at 4
[nameMissing ]
1.2.3The input string '1.2.3' was not in a correct format.
Format([price], "C", "!!")Unknown culture '!!'
Format(2.5, "X")Format specifier was invalid.
Upper("abc)Missing closing quote of the text at 6
[customer].nameType JsonElement is not registered (AddTypeReference)
Math.Max(1, 2)Member Max on null

Math.Max(…) ohne AddTypeReference(typeof(Math)) liest Math als (fehlendes) Feld – daher „Member Max on null“.

Falsche Daten lösen keinen Fehler aus (außer in GS1 und bei ungültigen Kulturnamen): Unbekannte Felder sind leer, Text, der keine Zahl ist, zählt als 0, Text, der kein Datum ist, ergibt 0001-01-01. Etiketten vor dem Druck mit Label.Validate(record) und den Etikettentests prüfen.

15Rezepte

AufgabeAusdruckErgebnis
Preis mit der Währung des DatensatzesFormat([price], "C", [culture])1.234,50 €
Durchgestrichener alter Preis nur, wenn höherIf([oldPrice] > [price], Format([oldPrice], "C", [culture]), "")1.499,00 €
Ersparnis in Prozent"-" + Format(1 - [price] / [oldPrice], "P0", "de-DE")-18 %
Preis mit Steuer, 2 NachkommastellenFormat([price] * 1.2, "N2", "de-DE") + " € inkl. 20 % MwSt."1.481,40 € inkl. 20 % MwSt.
Grundpreis (pro kg)Format([price] / [weight], "#,##0.00", "de-DE") + " €/kg"2.703,09 €/kg
Mindesthaltbarkeit: heute + 30 Tage"Mindestens haltbar bis " + Format(AddDays(Today(), 30), "dd.MM.yyyy")Mindestens haltbar bis 21.11.2026
Mindesthaltbarkeit aus einem DatumstextFormat(AddMonths(ToDate([deDate], "dd.MM.yyyy"), 6), "MM/yyyy")04/2027
Herstellungsdatum, ISOFormat(Now(), "yyyy-MM-dd HH:mm")2026-10-22 14:30
Gewicht in g oder kgIf([weight] < 1, Format([weight] * 1000, "0 'g'"), Format([weight], "0.00 'kg'", "de-DE"))457 g
Gewicht mit 3 NachkommastellenFormat([weight], "0.000 'kg'", "de-DE")0,457 kg
Barcode-Daten mit PrüfzifferGs1CheckDigit("400638" + PadLeft([serial], 6, "0"))4006380000421
Seriennummer mit Präfix"SN-" + PadLeft(LABEL_NUMBER, 5, "0")SN-00001
Seite x von yPAGE_NUMBER + "/" + TOTAL_PAGES1/3
Name: Initiale + NachnameUpper(Left([first], 1)) + ". " + [last]A. Schmidt
Adresszeile, leere Teile übersprungenTrim(Concat([customer.zip], " ", [customer.city], If(IsEmpty([nothing]), "", ", " + [nothing])))8010 Graz
Bedingter TextIf([qty] >= 10, "BULK", If([qty] > 1, "MULTI", "SINGLE"))MULTI
ErsatztextCoalesce([nothing], [customer.name], "unbekannt")ACME GmbH
Artikelnummer in Großbuchstaben ohne BindestrichUpper(Replace([sku], "-", ""))AB123
Preise aus Textfeldern vergleichenIf(Num([textOld]) > Num([textPrice]), "SALE", "")(leer)
GS1-128-Daten mit MindesthaltbarkeitGS1("01", [gtin], "15", Format(AddDays(Today(), 30), "yyMMdd"), "10", [lot])(01)09521234543213(15)261121(10)LOT42

16Stolperfallen

  • Text, der keine Zahl ist, wird als Text verglichen. "a10" < "a9" ist wahr; zwei Zahltexte ("9.99", "19.99") werden als Zahlen verglichen.
  • + mit einem leeren Feld verbindet. [missing] + 1 + 1 ergibt "11"; Num([missing]) + 1 + 1 schreiben.
  • Datumswerte aus JSON/CSV sind Text. Format([date], "dd.MM.yyyy") druckt den Text unverändert; Format(ToDate([date]), …) verwenden, bei Texten, die nicht ISO sind, mit Muster: ToDate([deDate], "dd.MM.yyyy").
  • Keine Kultur → invariant. Format([price], "C") druckt ¤1,234.50; eine Kultur übergeben oder in C# label.Expressions.Culture setzen.
  • ar-SA und th-TH verwenden andere Kalender für Datumswerte.
  • Die Formate D/X brauchen ganze Zahlen: Format(2.5, "D3") löst einen Fehler aus; vorher runden oder "000" verwenden.
  • Tausendertrennzeichen lesen nur ToNumber/IsNumeric mit Kultur-Argument; Num und Umwandlungen ohne Kultur brauchen Zahlen ohne Trennzeichen.
  • Text, der kein Datum bzw. keine Zahl ist, löst keinen Fehler aus: Er wird zu 0001-01-01 bzw. 0.
  • not bindet stärker als =: not ([a] = 1) schreiben.
  • Beide Zweige von If werden ausgewertet. Ein GS1()-Aufruf mit leerem Wert löst auch in dem Zweig einen Fehler aus, der nicht gewählt wird.
  • Einheitentexte in Formaten: in Anführungszeichen setzen ("0.0 'kg'").
  • Anführungszeichen im Label-JSON: "expression": "Format([price], \"C\", \"de-DE\")" – die JSON-Escapes gehören nicht zum Ausdruck.
  • Grenzen der Engine: höchstens 256 Ebenen verschachtelter Klammern, Argumente und unärer Operatoren (ExpressionEngine.MaxNesting); tiefere Ausdrücke lösen FormatException aus, statt den Stack zu erschöpfen. Der Online-Builder begrenzt Länge und Verschachtelung zusätzlich.