Created
November 6, 2025 23:13
-
-
Save ichernev/53582083a9144556b4e0dbf6df2ef51c to your computer and use it in GitHub Desktop.
Python script that converts VCF into CSV
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # import vcf | |
| # with open('contacts.vcf', 'r') as f: | |
| # vcf_reader = vcf.Reader(f) | |
| # i = 0 | |
| # for record in vcf_reader: | |
| # print('{} {}'.format(i, record)) | |
| # i += 1 | |
| import json | |
| import quopri | |
| import csv | |
| def dec_str(kp, v): | |
| if 'ENCODING=QUOTED-PRINTABLE' in kp: | |
| cs = list(filter(lambda p: p.startswith('CHARSET='), kp)) | |
| if len(cs) == 1: | |
| csx = cs[0][len('CHARSET='):] | |
| else: | |
| csx = 'UTF-8' | |
| return quopri.decodestring(v).decode(csx) | |
| else: | |
| return v | |
| def read_vcf(filename): | |
| contacts = [] | |
| with open('contacts.vcf', 'r') as f: | |
| inB64 = False | |
| contact = None | |
| for line in f: | |
| line = line.strip() | |
| if line == 'BEGIN:VCARD': | |
| contact = {} | |
| continue | |
| if line == 'VERSION:2.1': | |
| continue | |
| if inB64: | |
| if not line: | |
| inB64 = False | |
| continue | |
| # accum b64 here | |
| try: | |
| kraw, vraw = line.split(':', 1) | |
| except: | |
| print('BAD line was {}'.format(line)) | |
| continue | |
| kp = kraw.split(';') | |
| vp = vraw.split(';') | |
| if 'ENCODING=BASE64' in kp: | |
| inB64 = True | |
| continue | |
| if kp[0] == 'N': | |
| contact['last_name'] = dec_str(kp, vp[0]) | |
| contact['first_name'] = dec_str(kp, vp[1]) | |
| elif kp[0] == 'FN': | |
| contact['full_name'] = dec_str(kp, vp[0]) | |
| elif kp[0] == 'TEL': | |
| phones = contact.get('phones', []) | |
| phones.append(vp[0]) | |
| if 'PREF' in kp and len(phones) > 1: | |
| phones[0], phones[-1] = phones[-1], phones[0] | |
| contact['phones'] = phones | |
| elif kraw == 'END' and vraw == 'VCARD': | |
| contacts.append(contact) | |
| # print(json.dumps(contact, indent=4)) | |
| # print('----') | |
| continue | |
| else: | |
| print('UNKNOWN key {}'.format(kp[0])) | |
| return contacts | |
| def dump_in_csv(contacts, filename): | |
| with open(filename, 'w', newline='') as f: | |
| csv_w = csv.writer(f, delimiter=',', | |
| quotechar='"', quoting=csv.QUOTE_MINIMAL) | |
| csv_w.writerow(['First Name', 'Last Name', 'Full Name', | |
| 'Phone', 'Phone 2', 'Phone 3']) | |
| for c in contacts: | |
| phones = c.get('phones', []) | |
| get_phone = lambda i: phones[i] if i < len(phones) else '' | |
| csv_w.writerow([c.get('first_name', ''), c.get('last_name', ''), | |
| c.get('full_name', ''), get_phone(0), | |
| get_phone(1), get_phone(2)]) | |
| dump_in_csv(read_vcf('contacts.vcs'), 'contacts.csv') | |
| # for c in filter(lambda c: len(c.get('phones', [])) > 1, contacts): | |
| # print(json.dumps(c, indent=4)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment