from pathlib import Path import re, csvsrc = Path(“/mnt/data/Pasted markdown(2).md”) raw_lines = src.read_text(encoding=”utf-8″).splitlines()# Remove markdown fences/header. lines = [ln for ln in raw_lines if ln.strip() != ““`”] if lines and lines[0].startswith(“CERTIFICATE”): lines = lines[1:]# Split into blank-line-delimited business records. blocks = [] current = [] for ln in lines: if not ln.strip(): if current: blocks.append(current) current = [] else: current.append(ln) if current: blocks.append(current)meta_re = re.compile( r”^\s*(?:(\d{10})\s+)?(\d{6})\s+(\d+)\s+([YN])\s+(\d{2}-\d{2}-\d{4})\s+” ) city_re = re.compile(r”^(.*?)\s+([A-Z]{2})\s+(\d{5}(?:-\d{4})?)$”) city_nozip_re = re.compile(r”^(.*?)\s+([A-Z]{2})$”)records = []for block in blocks: first = block[0] m = meta_re.match(first) if not m: continuecertificate, naics, employees, res, date_estd = m.groups() # Fixed-width source columns: business/location at 48:86, mailing at 86+ left_first = first[48:86].strip() if len(first) > 48 else “” right_first = first[86:].strip() if len(first) > 86 else “” business_name = left_first mailing_name = right_first left_parts = [] right_parts = [] phone = “” fax = “” for ln in block[1:]: left = ln[48:86].strip() if len(ln) > 48 else “” right = ln[86:].strip() if len(ln) > 86 else “” # Phone/fax line is located in the business/location column. if left and re.fullmatch(r”\d{10}(?:\s+\d{10})?”, left): nums = re.findall(r”\d{10}”, left) if nums: phone = nums[0] if len(nums) > 1: fax = nums[1] continue if left: left_parts.append(left) if right: right_parts.append(right)# Parse physical city/state/zip from final left line when possible. loc_city = loc_state = loc_zip = “” loc_address_parts = left_parts[:] if loc_address_parts: cm = city_re.match(loc_address_parts[-1]) if cm: loc_city, loc_state, loc_zip = cm.groups() loc_address_parts = loc_address_parts[:-1]# Parse mailing city/state/zip from final right line when possible. mail_city = mail_state = mail_zip = “” mail_address_parts = right_parts[:] if mail_address_parts: cm = city_re.match(mail_address_parts[-1]) if cm: mail_city, mail_state, mail_zip = cm.groups() mail_address_parts = mail_address_parts[:-1] else: cm2 = city_nozip_re.match(mail_address_parts[-1]) if cm2: mail_city, mail_state = cm2.groups() mail_address_parts = mail_address_parts[:-1]# Split first/second address lines while preserving any extra pieces. loc_line1 = loc_address_parts[0] if len(loc_address_parts) > 0 else “” loc_line2 = ” | “.join(loc_address_parts[1:]) if len(loc_address_parts) > 1 else “” mail_line1 = mail_address_parts[0] if len(mail_address_parts) > 0 else “” mail_line2 = ” | “.join(mail_address_parts[1:]) if len(mail_address_parts) > 1 else “”records.append({ “Certificate”: certificate or “”, “NAICS”: naics, “Employees”: employees, “Residential (Y/N)”: res, “Date Established”: date_estd, “Business Name”: business_name, “Location Address Line 1”: loc_line1, “Location Address Line 2”: loc_line2, “Location City”: loc_city, “Location State”: loc_state, “Location ZIP”: loc_zip, “Phone”: phone, “Fax”: fax, “Mailing Name / Contact”: mailing_name, “Mailing Address Line 1”: mail_line1, “Mailing Address Line 2”: mail_line2, “Mailing City”: mail_city, “Mailing State”: mail_state, “Mailing ZIP”: mail_zip, })out = Path(“/mnt/data/gwinnett_business_license_contacts.csv”) fieldnames = list(records[0].keys()) with out.open(“w”, newline=””, encoding=”utf-8-sig”) as f: writer = csv.DictWriter(f, fieldnames=fieldnames) writer.writeheader() writer.writerows(records)print(f”Created: {out}”) print(f”Records: {len(records)}”) print(f”Columns: {len(fieldnames)}”) print(“\nFirst 5 rows:”) for row in records[:5]: print(row)
What do you think?
Leave a Reply

Your email address will not be published. Required fields are marked *

More Cleaning Tips & Hacks