- 1. Strings
- 1.1. Overview
- 1.2. String Types
- 1.3. ASCII String Syntax
- 1.4. Hexadecimal String Syntax
- 1.5. String Operations
- 1.6. String Manipulation Patterns
- 1.7. String Searching
- 1.8. String Conversion
- 1.9. String Encoding
- 1.10. String Performance
- 1.11. String Best Practices
- 1.12. Common String Patterns
- 1.13. Common Pitfalls
- 1.14. Advanced String Techniques
- 1.15. See Also
1. Strings
Strings are sequences of 8-bit bytes used to represent text and binary data in PostScript. They are versatile composite objects that support both character data and arbitrary binary content.
1.1. Overview
PostScript strings are mutable byte sequences with indexed access. Unlike some languages where strings are immutable, PostScript strings can be modified in place. Strings serve dual purposes: representing text for display and storing binary data for images and other purposes.
1.2. String Types
PostScript supports two string notations: ASCII strings and hexadecimal strings.
1.2.1. ASCII Strings
ASCII strings are enclosed in parentheses ( and ):
(Hello, World!) % Simple text
(Line 1\nLine 2) % With newline
() % Empty string
(Text with (nested) parens) % Balanced parentheses
1.2.2. Hexadecimal Strings
Hexadecimal strings are enclosed in angle brackets < and >:
<48656C6C6F> % "Hello" in hex
<> % Empty string
<41 42 43> % "ABC" (whitespace ignored)
<416> % "A`" (odd digits padded with 0)
1.2.3. String Type Comparison
| Aspect | ASCII String | Hex String | Result |
|---|---|---|---|
Syntax |
|
|
Both create stringtype |
Content |
Characters |
Hex digits |
Same internal format |
Escapes |
Supported |
Not needed |
Both can represent any byte |
Readability |
Text-friendly |
Binary-friendly |
Use case dependent |
Type |
/stringtype |
/stringtype |
Identical type |
1.3. ASCII String Syntax
1.3.1. Basic Characters
Most characters can appear literally in ASCII strings:
(ABC) % Letters
(123) % Digits
(Hello, World!) % Punctuation
(Symbols: !@#$%^&*) % Special characters
1.3.2. Escape Sequences
Special characters require escape sequences:
| Sequence | Name | Description |
|---|---|---|
|
Newline |
Line feed (ASCII 10) |
|
Return |
Carriage return (ASCII 13) |
|
Tab |
Horizontal tab (ASCII 9) |
|
Backspace |
Backspace (ASCII 8) |
|
Form feed |
Form feed (ASCII 12) |
|
Backslash |
Literal backslash |
|
Left paren |
Literal left parenthesis |
|
Right paren |
Literal right parenthesis |
|
Octal |
Byte with octal value (1-3 digits) |
|
Continue |
Line continuation (ignored) |
% Control characters
(Line1\nLine2) % Two lines
(Tab\there) % Tab-separated
(Ring\b\b\b) % Backspace
% Special characters
(Backslash: \\) % Single backslash
(Parens: \(\)) % Literal parentheses
% Octal codes
(\101\102\103) % ABC
(\000\377) % NULL and 255
% Line continuation
(Long string \
continues here) % Backslash-newline ignored
1.4. Hexadecimal String Syntax
1.4.1. Hex Digit Pairs
Each pair of hex digits represents one byte:
<48> % Single byte: 72 (ASCII 'H')
<4142> % Two bytes: "AB"
<48656C6C6F> % Five bytes: "Hello"
1.4.2. Whitespace Handling
Whitespace is ignored in hex strings:
% These are equivalent:
(414243)
<41 42 43>
<41
42
43>
1.5. String Operations
1.5.1. Accessing Elements
| Operator | Stack Effect | Description |
|---|---|---|
|
|
Get byte at index |
|
|
Set byte at index |
|
|
Extract substring |
|
|
Replace substring |
|
|
Get string length |
% get - returns byte value (integer)
(ABC) 0 get % Returns 65 (ASCII 'A')
(ABC) 1 get % Returns 66 (ASCII 'B')
% put - modifies byte
(ABC) dup 0 88 put % Changes to (XBC)
% getinterval - substring
(Hello, World!) 0 5 getinterval % Returns (Hello)
(Hello, World!) 7 5 getinterval % Returns (World)
% putinterval - replace part
(Hello, World!) dup 7 (Moon) putinterval
% Result: (Hello, Moon!)
% length - byte count
(Hello) length % Returns 5
<4142> length % Returns 2
1.5.2. String Creation
| Operator | Stack Effect | Description |
|---|---|---|
|
|
Create string of length |
|
|
Convert to string |
|
|
Search from start |
|
|
Search anywhere |
% Create empty string
10 string % 10-byte string (uninitialized)
% Convert to string
42 10 string cvs % Returns (42)
/name 10 string cvs % Returns (name)
3.14 10 string cvs % Returns (3.14)
% String operations
(Hello, World!) (World) search {
% Found: returns (!) (World) (Hello, )
pop pop pop
} if
1.6. String Manipulation Patterns
1.6.1. String Concatenation
/Concat {
% in: string1 string2
% out: combined-string
2 copy length exch length add string
dup 0 4 index putinterval
dup 3 index length 3 index putinterval
3 1 roll pop pop
} def
(Hello, ) (World!) Concat % Returns (Hello, World!)
1.6.2. String Copying
/StringCopy {
% in: string
% out: copy
dup length string
dup 0 3 index putinterval
exch pop
} def
(Original) StringCopy % Independent copy
1.6.3. Character Replacement
/ReplaceChar {
% in: string old-char new-char
% out: modified-string (in-place)
3 -1 roll dup length 0 exch 1 sub {
2 index 1 index get % Get character
4 index eq { % If matches old
2 index 1 index 3 index put
} if
pop
} for
pop pop
} def
(Hello) (l) 0 get (L) 0 get ReplaceChar
% Returns (HeLLo)
1.6.4. String Trimming
/TrimLeft {
% in: string
% out: trimmed-string
dup 0 1 2 index length 1 sub {
1 index exch get % Get character
dup 32 eq % Space
exch 9 eq or % Or tab
not { exit } if
pop
} for
% Create substring from non-space position
1 index length 1 index sub
2 index 3 1 roll getinterval
exch pop
} def
( Hello ) TrimLeft % Returns (Hello )
1.7. String Searching
1.7.1. anchorsearch Operator
Searches from the beginning of a string:
% Success case
(Hello, World!) (Hello) anchorsearch {
% Stack: (, World!) (Hello)
exch =only ( ... ) print =
} {
(Not found) =
} ifelse
% Failure case
(Hello, World!) (World) anchorsearch {
% Not executed
} {
(Not at start) =
} ifelse
1.7.2. search Operator
Searches anywhere in a string:
% Find substring
(The quick brown fox) (quick) search {
% Stack: ( brown fox) (quick) (The )
(Found at position: ) print
length =
} {
(Not found) =
} ifelse
% Multiple occurrences
/FindAll {
% in: string pattern
% out: count
0 3 1 roll % counter
{
2 copy search {
% Found one
pop pop
length 0 exch getinterval
3 -1 roll 1 add 3 1 roll
} {
pop pop exit
} ifelse
} loop
exch pop exch pop
} def
(aabbaabb) (aa) FindAll % Returns 2
1.8. String Conversion
1.8.1. Numeric to String
% Integer conversion
42 10 string cvs % (42)
-17 10 string cvs % (-17)
% Real conversion
3.14159 20 string cvs % (3.14159)
-2.5 10 string cvs % (-2.5)
% Radix representation
16#FF 10 string cvs % (255) - decimal output
1.9. String Encoding
1.9.1. ASCII Encoding
Standard ASCII characters (0-127):
% Printable ASCII (32-126)
(ABCDEFGHIJKLMNOPQRSTUVWXYZ)
(abcdefghijklmnopqrstuvwxyz)
(0123456789)
(!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~)
% Control characters (0-31, 127)
<00 01 02 03 04 05 06 07> % NUL SOH STX ETX EOT ENQ ACK BEL
<08 09 0A 0B 0C 0D 0E 0F> % BS HT LF VT FF CR SO SI
1.9.2. Extended ASCII
Bytes 128-255 represent extended characters:
% Latin-1 extended characters
<C0 C1 C2 C3 C4 C5> % À Á Â Ã Ä Å
<E0 E1 E2 E3 E4 E5> % à á â ã ä å
% Symbol characters
<A9> % © (copyright)
<AE> % ® (registered)
<B0> % ° (degree)
1.9.3. UTF-8 Considerations
PostScript strings are byte sequences - UTF-8 requires multi-byte handling:
% UTF-8 encoded string (manual)
<
48 65 6C 6C 6F % "Hello"
20 % Space
E4 B8 96 E7 95 8C % "世界" (World in Chinese)
>
% Length is bytes, not characters
dup length = % 11 bytes (not 8 characters)
1.10. String Performance
1.10.1. String Allocation
% SLOW - repeated concatenation
()
1 1 100 {
10 string cvs
2 copy length exch length add string
dup 0 4 index putinterval
dup 3 index length 3 index putinterval
3 1 roll pop pop
} for
% FAST - pre-calculate size
0 1 1 100 {
10 string cvs length add
} for
string
% ... then fill ...
1.11. String Best Practices
1.11.1. Choose Appropriate Representation
% Use ASCII for text
(Hello, World!) % GOOD - readable
% Use hex for binary data
<89504E470D0A1A0A> % PNG signature
<FEFF> % UTF-16 BOM
% Use hex for control characters
<00 1B 7F> % NUL ESC DEL
1.12. Common String Patterns
1.12.1. String Builder
/StringBuilder {
% Create builder
<<
/capacity 100
/length 0
/buffer 100 string
/append {
% in: builder string
% out: builder
% ... implementation ...
} bind
/toString {
% in: builder
% out: string
% ... implementation ...
} bind
>>
} def
1.12.2. String Tokenization
/Split {
% in: string delimiter
% out: array-of-strings
mark 3 1 roll % Mark for array
{
2 copy search {
% Found delimiter
4 1 roll pop % Keep part before delimiter
exch pop % Remove delimiter
dup length 0 eq { exit } if
} {
% No more delimiters
pop exit
} ifelse
} loop
pop % Remove delimiter
] % Create array
} def
(one,two,three) (,) Split % Returns [(one) (two) (three)]
1.12.3. Case Conversion
/ToLower {
% in: string
% out: lowercase-string (in-place)
0 1 2 index length 1 sub {
2 copy get % Get character
dup 65 ge 1 index 90 le and { % A-Z?
32 add % Add 32 for lowercase
2 index 3 1 roll put
} {
pop pop
} ifelse
} for
} def
(HELLO) dup ToLower % Returns (hello)
1.13. Common Pitfalls
1.13.1. String Mutability
% WRONG - shared reference
/str (Hello) def
/copy str def
copy 0 88 put % Modifies both!
% RIGHT - independent copy
/str (Hello) def
/copy str dup length string dup 0 3 index putinterval exch pop def
copy 0 88 put % Only modifies copy
1.13.2. Index Out of Bounds
% WRONG - no validation
(ABC) 10 get % rangecheck error
% RIGHT - validate index
/str (ABC) def
/idx 10 def
idx 0 ge idx str length lt and {
str idx get
} {
(Index out of bounds) =
null
} ifelse
1.14. Advanced String Techniques
1.14.1. String Hashing
/HashString {
% in: string
% out: hash-value
0 exch % accumulator
0 exch {
exch 31 mul add % hash = hash * 31 + char
65535 and % Keep in range
exch
} forall
pop
} def
(Hello) HashString % Produces hash value
1.14.2. String Interpolation
/Interpolate {
% in: template-string value-dict
% out: result-string
% Simple implementation:
% Replace ${key} with values from dict
% ... implementation ...
} def
(Hello, ${name}!)
<< /name (World) >>
Interpolate % Returns (Hello, World!)
1.14.3. String Comparison
/StrEqIgnoreCase {
% in: string1 string2
% out: bool
2 copy length exch length ne {
pop pop false
} {
true 3 1 roll
0 exch {
% Compare characters case-insensitively
2 index 2 index get % Get char from str1
dup 65 ge 1 index 90 le and { 32 add } if
3 index 3 index get % Get char from str2
dup 65 ge 1 index 90 le and { 32 add } if
ne {
pop pop pop pop false exit
} if
1 add
} forall
{ pop pop } if
} ifelse
} def
(Hello) (HELLO) StrEqIgnoreCase % true
1.15. See Also
-
Tokens - String token syntax
-
Arrays - Similar indexed structure
-
Objects - String object model
-
Data Types - String type details
-
string - Create strings
-
get - Access bytes
-
put - Modify bytes
-
search - Find substrings
-
anchorsearch - Prefix search
-
cvs - Convert to string