Why accented names break in vCard converters
You export your contacts from an old phone, convert the .vcf to a spreadsheet, open
it — and every name with an accent is wrecked. José has become
José. Müller is Müller. Škoda is
something worse. Names in Arabic, Greek or Cyrillic may be gone entirely.
The file is fine. Your contacts are fine. The converter made a specific, well-understood mistake, and once you have seen it you can spot it in about ten seconds.
What is actually in the file
Open a .vcf in any text editor — it is plain text. A contact from an older phone
often looks like this:
BEGIN:VCARD
VERSION:2.1
FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:Jos=C3=A9 Garc=C3=ADa
TEL;CELL:+34600123456
END:VCARD
The name is not stored as José García. It is stored as
Jos=C3=A9 Garc=C3=ADa, and the line announces exactly why:
ENCODING=QUOTED-PRINTABLE.
Quoted-printable, briefly
Quoted-printable is an old encoding for sending non-ASCII text through systems that only reliably
handled plain English characters. Any byte outside that safe range is written as an equals sign
followed by two hex digits. So the byte 0xC3 becomes the three characters
=C3.
The letter é in UTF-8 is not one byte — it is two: 0xC3 0xA9. Written
in quoted-printable that is =C3=A9. Same for í
(=C3=AD), ü (=C3=BC), and so on. Characters outside
Latin scripts often take three or four bytes.
The mistake
Here is the bug, in the form it usually takes. Decoding each escape straight into a character:
// wrong
value.replace(/=([0-9A-F]{2})/gi, (_, hex) =>
String.fromCharCode(parseInt(hex, 16))
);
Run that on Jos=C3=A9 and you get Jos followed by character
0xC3 and character 0xA9 — which, interpreted as individual Latin-1
characters, are à and ©. Hence José.
The two bytes were meant to be read together as one UTF-8 character. Decoding them separately splits a single letter into two wrong ones. That is the entire bug.
The fix
Collect the bytes first, then decode the whole sequence as UTF-8:
// right
const bytes = [];
for (let i = 0; i < value.length; i++) {
if (value[i] === '=' && /[0-9A-F]{2}/i.test(value.slice(i + 1, i + 3))) {
bytes.push(parseInt(value.slice(i + 1, i + 3), 16));
i += 2;
} else {
bytes.push(value.charCodeAt(i));
}
}
return new TextDecoder('utf-8').decode(new Uint8Array(bytes));
Same input, correct output: José García. This is what we use in
the open-source library
behind our converter, and the difference is genuinely those few lines.
Which files are affected
| vCard version | Where it comes from | Accent risk |
|---|---|---|
| 2.1 | Older Android exports, feature phones, some SIM backups | High — uses quoted-printable |
| 3.0 | iPhone, Google Contacts, Outlook | Low — plain UTF-8 |
| 4.0 | Newer standards-based apps | Low — plain UTF-8 |
So this mostly bites when you are rescuing contacts from an old phone — which is precisely when you least want to lose them.
Check your file in ten seconds
- Make a copy of the
.vcfand open the copy in Notepad or TextEdit. - Search for
QUOTED-PRINTABLE. - If it appears, your file is in the at-risk category — test any converter with a few contacts before trusting it with all of them.
-
If you see
VERSION:3.0or4.0and no quoted-printable, most tools will handle it correctly.
If you have already imported broken names
Do not fix them by hand. Re-convert from the original .vcf with a tool that handles
the encoding, then re-import. Search-and-replace on a mangled spreadsheet is unreliable because
several different original characters can collapse into the same wrong output — you cannot always
tell what it was supposed to be.
If you no longer have the original file, export again from the source device if you can. It is faster than repairing a few hundred names.
Why so many converters get this wrong
Mostly because it works fine in testing. Developers test with names like "John Smith", the conversion succeeds, and the bug never appears. It only surfaces for users whose names contain accents — which, from a European, Latin American or Asian perspective, is most people.
It is a small bug with an unfortunate distribution: harmless for the people writing the software, and a real problem for everyone else.