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)