^SF - Serialization Field
Increments the current field's data between copies according to a per-character mask.
^SF is the general form of serialization. ^SN counts in decimal; ^SF advances
an existing ^FD string one character position at a time, in the base each position
declares. That renders a sequence such as BL0000 … BL9999, BM0000, or one
in hexadecimal, or one with a fixed separator in the middle. Unlike ^SN it does
not replace ^FD; it masks the ^FD in its own field.
Syntax
^SFa,bSupport
Every documented parameter renders the same output Labelary produces.
The renderer parses ^SF and advances the data of the field it sits in, once per copy ^PQ prints. Each mask character counts its position through its own alphabet, a carry runs leftwards through the held positions and stops at the region's left edge, and the increment is read one character per position. ^PQ's replicates argument r sets how many output pages share one value. Labelary's report about a mask or increment width that differs from the field data has no counterpart here. Measured against Labelary on 2026-08-21. — not pinned by a test
Labelary renders this command.
Parameters
aSerialisation maskrequired · textSets the serialization scheme, one mask character per character of the field data. The mask is left-aligned to the data, so the characters it covers are the leading ones. Case matters: h counts through lower-case hex digits and H through upper-case ones. The guide limits mask and increment together to 3K.
- Invalid value
- not possible — any value is accepted. A mask character outside
dDoOhHaAnN%holds its position unchanged, exactly as%does, and a carry still passes through it. A mask of nothing but such characters, or an empty mask, serializes nothing. Measured against Labelary on 2026-08-21. - Test coverage
bIncrementoptional · textHow much to add at each copy, written in the alphabets the mask selects. It is right-aligned inside the region the mask covers, so a one-character increment steps that region's last position. Alphabetic positions count from A or a as zero, so B steps a letter by one, and a % holds a position unchanged.
- Default
- 1
- Invalid value
- not possible — any value is accepted. A character the position's alphabet does not hold counts as zero there, and so does a
%, a comma or a line break.^SFhas no third parameter: everything after the first comma is the increment. Measured against Labelary on 2026-08-21. - Test coverage
Behavior
Each mask character declares the alphabet its position counts through, and the case
it is written in is the case the counter prints. d and D count the ten digits,
o and O the eight octal ones, h the lower-case hexadecimal digits and H the
upper-case ones, a the lower-case letters and A the upper-case ones, n and N
all 36 alphanumerics — 0 to 9 followed by the letters. A % holds its position, and
so does any other character, which keeps a separator or a fixed prefix out of the
count.
A position that runs past the end of its alphabet carries into the position to its
left. The carry passes straight through a held position without changing it, and it
stops at the left edge of the region the mask covers, so the counter wraps rather
than grows: ^FD99^SFdd,1 prints 99, then 00, then 01.
The mask is left-aligned to the field data, so the characters it serializes are the
leading ones. A character the mask's alphabet cannot hold freezes its own position
and leaves the rest of the region counting: ^FD000E^SFhhhh,0010 prints 000E,
001E, 002E, because E is not a lower-case hexadecimal digit.
The increment uses the same alphabets as the mask, position by position, and it is
right-aligned inside the region the mask covers. A one-character increment therefore
steps that region's last position. In a letter position the count starts at A or
a as zero, so an increment of B steps a letter by one and F steps it by five.
A position that must not advance needs a % in the increment string as well as an
alphabet character in the mask. Any character the position cannot represent counts
as zero there.
^SF sits inside the field whose data it advances, either side of the ^FD, and its
reach ends at the ^FS that closes that field. Where a field carries both an ^SN
and an ^SF, the last of the two is the one whose increment runs.
The mask and the increment together must not exceed 3K, which no realistic field approaches. All of the above was measured against Labelary on 2026-08-21.
Differences from the specification
Labelary against the ZPL II guide
Where Labelary — our compatibility target — behaves differently from the printed specification.
- The guide aligns the mask to the right-most characters of the
^FDstring. Labelary aligns it to the left-most ones instead, and reports the width difference without refusing the field. We measured this on 2026-08-21:^FD12345^SFdd,1with^PQ3prints12345,13345,14345on Labelary, where the guide's rule would give12345,12346,12347. Labelary also answersField data length (5) does not match ^SF mask length (2). Give the mask the full width of the field data and the two rules agree. — pinned bytest_sf_mask_narrower_than_the_data_counts_from_the_left ^SFtakes a mask and an increment, and Labelary reads everything after the first comma as the increment. We measured this on 2026-08-21:^FD0000^SFdddd,0001,9reports^SF increment length (6)and steps by 109 a copy, because the comma counts as a zero in its position. — not pinned by a test^SNindexes at most the twelve right-most digits of its counter.^SFhas no such limit on Labelary: measured 2026-08-21, all fourteen digits of^FD99999999999999^SFdddddddddddddd,00000000000001take part and the value wraps to fourteen zeros. — not pinned by a test
zpl.tools against Labelary
Where our output differs from Labelary for the same input. These are the differences that break a migration.
- Labelary reports a mask or an increment whose length differs from the field data:
Field data length (5) does not match ^SF mask length (2)and the same sentence for the increment, both on the^FD. The renderer serializes the field the same way and says nothing. Measured 2026-08-21; the rendered label is identical either way. — pinned bytest_sf_mask_narrower_than_the_data_counts_from_the_left
Example
Two serialised fields on the same label. The first counts the four trailing digits and carries into the letters, so the three copies read BL0000, BL0001, BL0002. The second holds its hyphen with a % in the mask and a matching % in the increment, giving BL00-0, BL01-1, BL02-2:
^XA
^FO40,40^A0N,50,50^FDBL0000^SFAAdddd,1^FS
^FO40,120^A0N,50,50^FDBL00-0^SFAAdd%d,1%1^FS
^PQ3
^XZ
Related commands
^SNSerialization DataMakes the current field a counter that steps by a fixed amount for each copy `^PQ` prints.^FDField DataSupplies the text or barcode content of the field.^PQPrint QuantityPrints the label more than once, the one command here that changes how many pages come back.^FNField NumberNumbers a field so a stored format can fill it in later.