Skip to content

Instantly share code, notes, and snippets.

@pschichtel
Created December 2, 2018 21:22
Show Gist options
  • Save pschichtel/5ac4a149995a1ff8f89fbc4cd7867f96 to your computer and use it in GitHub Desktop.
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.
# 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