Writing

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 versionWhere it comes fromAccent 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

  1. Make a copy of the .vcf and open the copy in Notepad or TextEdit.
  2. Search for QUOTED-PRINTABLE.
  3. 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.
  4. If you see VERSION:3.0 or 4.0 and 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.