Created
December 2, 2018 21:22
-
-
Save pschichtel/5ac4a149995a1ff8f89fbc4cd7867f96 to your computer and use it in GitHub Desktop.
The is a script to convert the phonebook CSV export from the EuriTel Pro software (used for old Ascom/Swissvoice analog phones together with the "PC-Dialer III" device) to the CSV schema supported by outlook and sipgate.de. It applies a bunch of assumptions to extract customer numbers and other contact details to the proper fields.
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
# coding=utf-8 | |
import sys | |
import csv | |
import vobject | |
import re | |
whitespace = re.compile('\s+') | |
numberCleaner = re.compile('^.*?(\d+).*$') | |
customerIdFormat = re.compile('^\S*?\d+$') | |
umlautSubs = [ | |
('ae', 'ä'), | |
('oe', 'ö'), | |
('ue', 'ü'), | |
('Ae', 'Ä'), | |
('Oe', 'Ö'), | |
('Ue', 'Ü') | |
] | |
misterShorts = ['h.', 'hr.', 'hr', 'h'] | |
missesShorts = ['f.', 'fr.', 'fr', 'f'] | |
doctorShorts = ['dr.', 'dr'] | |
def read_csv_phonebook(f): | |
with open(f) as inputFile: | |
entries = [row for row in csv.reader(inputFile, delimiter=';', quotechar='"')] | |
header = entries[0] | |
body = entries[1:] | |
return [dict(zip(header, row)) for row in body] | |
def extract_vcard_name(entry): | |
return vobject.vcard.Name(entry['Name']) | |
def remove_whitespace(s): | |
return re.sub(whitespace, '', s) | |
def cleanup_number(s): | |
return re.sub(numberCleaner, '\\1', remove_whitespace(s)) | |
def is_num(s): | |
if not s: | |
return False | |
return all([c.isdigit() for c in s]) | |
def split_name(name): | |
trimmed = name.strip() | |
if not trimmed: | |
return [] | |
return whitespace.split(trimmed) | |
def is_customer_id(s): | |
if customerIdFormat.match(s): | |
return True | |
return False | |
def umlauts(s): | |
for search, replace in umlautSubs: | |
s = re.sub('([^aeuoi])' + search, '\\1' + replace, s) | |
return s | |
def find_index_of_any(parts, needles): | |
for needle in needles: | |
try: | |
return parts.index(needle) | |
except: | |
pass | |
def customer_id_from_name(parts): | |
if not parts: | |
return None, parts | |
try: | |
i = find_index_of_any(parts, ['KN', 'D']) | |
rest = parts[0:i] | |
id = ''.join(parts[i + 1:]) | |
return id, rest | |
except: | |
if is_customer_id(parts[-1]): | |
id = parts[-1] | |
if id[0:2] == 'KN': | |
id = id[2:] | |
rest = parts[0:-1] | |
return id, rest | |
else: | |
return None, parts | |
def fix_title(s): | |
if s.lower() in misterShorts: | |
return "Herr" | |
if s.lower() in missesShorts: | |
return "Frau" | |
if s.lower() in doctorShorts: | |
return "Dr." | |
return s | |
def normalize_name_part(s): | |
with_umlauts = umlauts(s) | |
with_titles = fix_title(with_umlauts) | |
return with_titles | |
def extract_title(parts): | |
possible = ['Frau', 'Herr', 'Dr.'] | |
titles = [] | |
for possibleTitle in possible: | |
if possibleTitle in parts: | |
titles.append(possibleTitle) | |
rest = [p for p in parts if p not in possible] | |
return rest, ' '.join(titles) | |
contacts = [read_csv_phonebook(f) for f in sys.argv[1:]] | |
contacts = [b for a in contacts for b in a] | |
print('Vornamen;Nachname;Anrede;Suffix;Initialen;Webseite;Geschlecht;Geburtstag;Jahrestag;Ort;Sprache;Internet Frei/Gebucht;Notizen;E-Mail-Adresse;E-Mail 2: Adresse;E-Mail 3: Adresse;Haupttelefon;Telefon (privat);Telefon (privat 2);Mobiltelefon;Pager;Fax privat;Adresse privat;Straße privat;Straße privat 2;Straße privat 3;Postfach privat;Ort privat;Bundesland/Kanton privat;Postleitzahl privat;Land/Region privat;Partner;Kinder;Name des/r Vorgesetzten;Assistent(in);Empfohlen von;Telefon Firma;Telefon geschäftlich;Telefon geschäftlich 2;Fax geschäftlich;Telefon Assistent;Firma;Position;Abteilung;Büro;Organisationsnr.;Beruf;Konto;Adresse geschäftlich;Straße geschäftlich;Straße geschäftlich 2;Straße geschäftlich 3;Postfach geschäftlich;Ort geschäftlich;Region geschäftlich;Postleitzahl geschäftlich;Land/Region geschäftlich;Weiteres Telefon;Weiteres Fax;Weitere Adresse;Weitere Straße;Weitere Straße 2;Weitere Straße 3;Weiteres Postfach;Weiterer Ort;Weiteres/r Bundesland;Weitere Postleitzahl;Weiteres Land/Region;Rückmeldung;Autotelefon;ISDN;Radio Phone;Telefon für Hörbehinderte;Telex;Benutzer 1;Benutzer 2;Benutzer 3;Benutzer 4;Stichwörter;Reisekilometer;Hobby;Abrechnungsinformation;Verzeichnisserver;Vertraulichkeit;Priorität;Privat;Kategorien') | |
for entry in contacts: | |
v = vobject.vCard() | |
v.add('n') | |
v.n.value = extract_vcard_name(entry) | |
v.add('fn') | |
#print(v.serialize()) | |
firstName = entry['Vorname'] | |
surname = entry['Name'] | |
note = entry['Notiz'] | |
customerId = '' | |
street = entry['Strasse'] | |
postalCode = entry['Postleitzahl'] | |
place = entry['Ort'] | |
emailOffice = remove_whitespace(entry['E-Mail Büro']) | |
emailPrivate = remove_whitespace(entry['E-Mail Privat']) | |
numberOffice = cleanup_number(entry['Telefon Büro']) | |
numberPrivate = cleanup_number(entry['Telefon Privat']) | |
numberFax = cleanup_number(entry['Fax']) | |
numberMobile = cleanup_number(entry['Telefon Handy']) | |
numberPager = cleanup_number(entry['Pager']) | |
numberOther = cleanup_number(entry['Andere']) | |
numberUrl = cleanup_number(entry['URL']) | |
emails = {} | |
if emailOffice != '': | |
if is_customer_id(emailOffice): | |
customerId = emailOffice | |
else: | |
emails['office'] = emailOffice | |
if emailPrivate != '': | |
if is_customer_id(emailPrivate): | |
customerId = emailPrivate | |
else: | |
emails['private'] = emailPrivate | |
numbers = {} | |
if numberOffice != '': | |
numbers['office'] = numberOffice | |
if numberPrivate != '': | |
numbers['private'] = numberPrivate | |
if numberFax != '': | |
numbers['fax'] = numberFax | |
if numberMobile != '': | |
numbers['mobile'] = numberMobile | |
if numberPager != '': | |
numbers['pager'] = numberPager | |
if numberOther != '': | |
numbers['other'] = numberOther | |
if numberUrl != '': | |
numbers['office'] = numberUrl | |
surnameParts = split_name(surname) | |
firstNameParts = split_name(firstName) | |
customerIdSurname, surnameParts = customer_id_from_name(surnameParts) | |
customerIdFirstName, firstNameParts = customer_id_from_name(firstNameParts) | |
if customerIdSurname: | |
customerId = customerIdSurname | |
if customerIdFirstName: | |
customerId = customerIdFirstName | |
note = '' | |
if customerId: | |
note = "Kundennummer: " + customerId | |
surnameParts = [normalize_name_part(p) for p in surnameParts] | |
firstNameParts = [normalize_name_part(p) for p in firstNameParts] | |
surnameParts, title = extract_title(surnameParts) | |
if not title: | |
firstNameParts, title = extract_title(firstNameParts) | |
finalSurname = ' '.join(surnameParts) | |
finalFirstName = ' '.join(firstNameParts) | |
print('{};{};{};;;;;;;{};;;{};{};{};;{};{};{};{};{};{};;{};;;;{};;{};;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;'\ | |
.format(finalFirstName, finalSurname, title, place, 'Deutsch', note, emails.get('office', ''), emails.get('private', ''), numbers.get('office', ''), numbers.get('private', ''), numbers.get('other', ''), numbers.get('mobile', ''), numbers.get('pager', ''), numbers.get('fax', ''), street, place, postalCode)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment