Ten characters in the GSM 7-bit alphabet are not in its basic table. They sit in an extension table, and each one is sent as an escape code followed by a second code, so it takes up two of the 160 units in a message instead of one. The ones you are likely to type are ^, {, }, [, ], ~, \, | and €. A message that uses them is still GSM-7. It just fills up faster than its character count suggests.
The full list
| Character | Name | Sent as | The second code alone means |
|---|---|---|---|
^ |
circumflex | 0x1B 0x14 | Λ |
{ |
left curly bracket | 0x1B 0x28 | ( |
} |
right curly bracket | 0x1B 0x29 | ) |
\ |
backslash | 0x1B 0x2F | / |
[ |
left square bracket | 0x1B 0x3C | < |
~ |
tilde | 0x1B 0x3D | = |
] |
right square bracket | 0x1B 0x3E | > |
| |
vertical bar | 0x1B 0x40 | ¡ |
€ |
euro sign | 0x1B 0x65 | e |
| form feed | page break (a control code) | 0x1B 0x0A | line feed |
The tenth entry, form feed, is a control code that the standard defines as a page break. You will not meet it in ordinary text. The complete basic table is in What is GSM-7?
How the escape works
A 7-bit code has 128 possible values, and the basic table fills every one of them. One value, 0x1B, is not a character but a signal. The standard, 3GPP TS 23.038, describes it this way: "This code is an escape to an extension of this table". When a phone reads 0x1B it looks up the next code in the extension table instead of the basic one.
So € travels as two codes, 0x1B then 0x65, and 0x65 by itself is the letter e. An opening square bracket is the escape followed by the code for <. That is the whole reason for the double cost: two 7-bit codes are transmitted. The same document spells out the consequence: "the number of displayable characters will reduce by one for every instance where the GSM 7 bit default alphabet extension table is used".
Providers describe it the same way. Twilio's documentation says "These escape characters count as two characters in a GSM-7-encoded message", and Vonage's says "Characters from the extended table require two characters to encode".
The pairings in the last column have a visible side effect. The standard says a receiver that does not understand the escape "shall display it as a space character". On such a device €5 would appear as a space followed by e5.
Counting units
The rule is simple: units = characters + the number of extension characters.
| Text | Characters | Extension characters | Units |
|---|---|---|---|
Price: €5 [approx] |
18 | 3 | 21 |
{"id":42,"ok":true} |
19 | 2 | 21 |
C:\Users\Sam\notes.txt |
22 | 3 | 25 |
In a short message the extra units do not matter. They matter near a limit. This promotion is 157 characters, which looks safely under 160:
Flash sale [48 hours]: 20% off orders over €50 with code SAVE20. Free UK delivery. Shop at example.com/sale ~ ends Sunday at midnight. Reply STOP to opt out.
It contains four extension characters: [, ], € and ~. That makes 161 units, one too many for a single message, so it is sent as two parts of 153 and 8.
Write (48 hours) with parentheses and replace the tilde with a hyphen, and the same 157 characters use 158 units. One message.
The SMS Character Counter shows the unit total and lists the extension characters it found, so you can see which ones are costing you.
The boundary rule
There is a second effect, and it only shows up in messages long enough to be split. The standard for concatenated messages, 3GPP TS 23.040, says: "A character represented by an escape-sequence shall not be split in the middle."
Each part is a separate short message, so an escape code at the end of one and its partner at the start of the next would arrive apart. The pair has to stay together. If a part has one unit left and the next character needs two, the whole pair moves to the following part and that last unit goes unused. The part carries 152 units instead of 153.
Usually this changes nothing. Occasionally it adds a part. Here is a constructed case:
- 152 ordinary characters, then
[, then 152 more ordinary characters - 305 characters in total, and 152 + 2 + 152 = 306 units
- 306 ÷ 153 = 2 exactly, so simple division predicts two parts
Packing the parts one at a time gives a different answer:
| Part | Contents | Units |
|---|---|---|
| 1 | the first 152 characters; the bracket does not fit in the one unit left | 152 |
| 2 | [ and the next 151 characters |
153 |
| 3 | the final character | 1 |
Three parts, not two. Move the bracket one place earlier, so that 151 characters come before it and 153 after, and the same 305 characters and 306 units pack into two full parts of 153.
The same rule sets how many of these characters fit in a row. Eighty euro signs are 160 units and fit in one message. Eighty-one are 162 units and need two parts, and the first part holds 76 of them (152 units), because a 77th would be cut in half.
This is why the part count is not simply the total divided by 153. A calculator has to place characters part by part, which is what ours does. The broader rules on splitting are in the guide to SMS character limits.
Not the same as a Unicode character
Two different things make an SMS longer than it looks, and they are worth keeping apart.
- An extension character costs one extra unit. The message stays in GSM-7 and the limit stays at 160.
- A character outside GSM-7 altogether, such as a curly quote, an accented letter the alphabet lacks, or an emoji, changes the encoding of the whole message to Unicode. The limit drops from 160 to 70.
A square bracket is a small cost. A curly apostrophe is a large one. The second case is explained in why one emoji can change the length of an SMS.
One more detail follows from this. If a message is already Unicode for another reason, the characters in the table above are no longer doubled. In UCS-2 each of them is a single 16-bit unit like any other, so swapping them out saves nothing.
What to do in practice
- Use parentheses for brackets and braces.
(and)are in the basic table and cost one unit each. Do this only where the meaning survives; in a code sample or a data format it will not. - Use a one-unit separator. A hyphen, comma or slash does the job of
|or~at half the cost. - Use a forward slash unless you need a real backslash. A Windows file path does need one. Most other uses do not.
- Keep the euro sign.
€is two units, but the usual replacement,EUR, is three. The same goes for~: writing "about" costs five units, not two. - Count the finished message. Placeholders such as
{name}are normally replaced before sending, so the braces in a template may never be transmitted. What matters is the text that goes out. - Ignore all of this when you are well under the limit. A 60-character message with a pair of brackets is one message either way.
These are the rules in the standard. Providers and carriers can apply their own limits and pricing on top, so use the unit count as an estimate of length and confirm anything that matters with a test message.