def normalize_contact(self, row: Dict) -> Dict: """Normalize contact data""" contact = {} for key, value in row.items(): if value and isinstance(value, str): value = value.strip() if value: contact[key] = value return contact
def create_vcf_card(self, contact: Dict, index: int) -> str: """Create single VCF card from contact data""" vcf_lines = [] # Begin vCard vcf_lines.append("BEGIN:VCARD") vcf_lines.append(f"VERSION:self.version") # Name (required) name = self.escape_vcf_text(contact.get('name', '')) if name: # Split name into parts name_parts = name.split(maxsplit=1) first_name = name_parts[0] if name_parts else '' last_name = name_parts[1] if len(name_parts) > 1 else '' vcf_lines.append(f"N:last_name;first_name;;;") vcf_lines.append(f"FN:name") else: vcf_lines.append(f"N:;;;index;") vcf_lines.append(f"FN:Contact index") # Phone number phone = self.format_phone(contact.get('phone', '')) if phone: vcf_lines.append(f"TEL;TYPE=CELL:phone") # Work phone (if available) work_phone = self.format_phone(contact.get('workphone', '')) if work_phone: vcf_lines.append(f"TEL;TYPE=WORK:work_phone") # Email email = self.escape_vcf_text(contact.get('email', '')) if email: vcf_lines.append(f"EMAIL;TYPE=INTERNET:email") # Company and Title company = self.escape_vcf_text(contact.get('company', '')) title = self.escape_vcf_text(contact.get('title', '')) if company: vcf_lines.append(f"ORG:company") if title: vcf_lines.append(f"TITLE:title") # Address address = self.escape_vcf_text(contact.get('address', '')) if address: vcf_lines.append(f"ADR;TYPE=WORK:;;address;;;;") # Website website = self.escape_vcf_text(contact.get('website', '')) if website: if not website.startswith(('http://', 'https://')): website = 'http://' + website vcf_lines.append(f"URL:website") # Birthday birthday = self.format_date(contact.get('birthday', '')) if birthday: vcf_lines.append(f"BDAY:birthday") # Notes notes = self.escape_vcf_text(contact.get('notes', '')) if notes: vcf_lines.append(f"NOTE:notes") # UID (unique identifier) import uuid vcf_lines.append(f"UID:uuid.uuid4()") # Revision date vcf_lines.append(f"REV:datetime.now().strftime('%Y%m%dT%H%M%SZ')") # End vCard vcf_lines.append("END:VCARD") vcf_lines.append("") # Empty line between cards return '\n'.join(vcf_lines) csv to vcf
def normalize_column_name(self, col: str) -> str: """Normalize column names to standard format""" col = col.lower().strip() mapping = 'name': 'name', 'fullname': 'name', 'displayname': 'name', 'phone': 'phone', 'mobile': 'phone', 'telephone': 'phone', 'cell': 'phone', 'workphone': 'phone', 'email': 'email', 'emailaddress': 'email', 'company': 'company', 'organization': 'company', 'title': 'title', 'jobtitle': 'title', 'position': 'title', 'address': 'address', 'street': 'address', 'website': 'website', 'url': 'website', 'webpage': 'website', 'birthday': 'birthday', 'bday': 'birthday', 'dob': 'birthday', 'notes': 'notes', 'comment': 'notes', 'description': 'notes' return mapping.get(col, col) row: Dict) ->
def format_date(self, date_str: str) -> str: """Format date for VCF (YYYYMMDD)""" if not date_str: return "" # Try different date formats formats = ['%Y-%m-%d', '%m/%d/%Y', '%d/%m/%Y', '%Y%m%d'] for fmt in formats: try: date_obj = datetime.strptime(date_str, fmt) return date_obj.strftime('%Y%m%d') except ValueError: continue return date_str.replace('-', '').replace('/', '') index: int) ->
# Check if input file exists if not os.path.exists(args.input): print(f"Error: Input file 'args.input' not found") return 1
def format_phone(self, phone: str) -> str: """Format phone number for VCF""" if not phone: return "" # Remove spaces and common separators phone = re.sub(r'[\(\)\s\-\.]', '', phone) # Add international prefix if missing if phone.startswith('0') and not phone.startswith('+'): phone = '+1' + phone[1:] # Default to US/Canada, customize as needed return self.escape_vcf_text(phone)
args = parser.parse_args()