🐸

联系人整理师

数据与文本工具python-data-tinkerer-41-the-contact-formatter
奖励: 180 XP
|

联系人整理师

你已经替人收过报名单、整理过配置、做过日志摘要。现在这批资料里还剩最后一份最容易被下一位协作者直接接走的东西:联系人名单。原表里有多余空格、重复邮箱、写法不一致的标签和城市信息,要是现在交接,后面的人发消息、分组跟进时就会一路卡住。

所以你这次要交出的,不只是一个练习结果,而是一份别人拿到就能继续工作的联系人清单。你会清理字段、按 email 保留 first-seen 联系人、用规则统一标签和城市分组,再把整理好的名单和摘要交给下一位组织者继续使用。

先看一个更小的动作:把一条联系人文本拆开并清理

先不要急着处理整份表。先看一个玩具例子:一条联系人记录里,名字、邮箱和标签都带着多余空白,我们可以先把这些局部动作做顺。

toy_row = "  Ava   Stone  , AVA@example.com , vip ; mentor ; vip "

name_text, email_text, tags_text = toy_row.split(",")
clean_name = " ".join(name_text.strip().split())
clean_email = email_text.strip().lower()
clean_tags = []

for raw_tag in tags_text.split(";"):
  tag = raw_tag.strip().lower()
  if tag != "" and tag not in clean_tags:
      clean_tags.append(tag)

print(clean_name)
print(clean_email)
print(clean_tags)

这个例子只是在示范动作:拆分、清理、去掉重复标签。它还没有读取今天的 CSV,也没有使用 JSON 规则,更没有完成最终 summary。

今天要交付什么:读取 messy_contacts.csvcontact_rules.json,交出一份可继续使用的联系人名单

脚本已经读取了 messy_contacts.csvcontact_rules.json。你要继续把联系人表逐行处理,清理字段,按 email 保留 first-seen 联系人,用 JSON 规则统一标签和城市分组,然后把结果放进 formatted_contactscontact_summary

1
先把 CSV 文本拆成真正要处理的记录行

raw_contacts_text.splitlines() 做出 contact_lines,再跳过表头,把真实联系人行放进 rows

2
逐行清理 name、email、tags 和 city

row.split(",") 拆出 4 个字段。名字可以用 " ".join(name_text.strip().split()) 压掉多余空白;email 要 strip().lower();city 也先清理空白。

3
按 first-seen email 去重,并用 JSON 规则统一标签和分组

如果清理后的 email 已经出现过,就增加 duplicate_emails_skipped 并跳过。否则继续处理标签:先 split(";"),再逐个 strip().lower(),然后用 contact_rules["tag_aliases"] 做统一映射。城市分组则从 contact_rules["city_groups"] 里读取。

4
整理最终结构和 summary

每个保留下来的联系人都应该放进 formatted_contacts,其中至少有 nameemailcitygrouptags。最后再做出 contact_summary,里面至少要有总行数、保留联系人数量、跳过的重复邮箱数、group 统计和 tag 统计。

把名单交给下一位组织者

只要名字、邮箱、标签和分组都稳定下来,下一位协作者就能直接继续联系、筛选和跟进,不必再回头问你原表到底是什么意思。

参考答案
点击展开
参考答案:
import json

CONTACTS_CSV = "messy_contacts.csv"
RULES_JSON = "contact_rules.json"

with open(CONTACTS_CSV, "r", encoding="utf-8") as file:
  raw_contacts_text = file.read().strip()

with open(RULES_JSON, "r", encoding="utf-8") as file:
  contact_rules = json.load(file)

print("Raw contacts text:")
print(raw_contacts_text)
print("Contact rules:", contact_rules)

contact_lines = raw_contacts_text.splitlines()
rows = contact_lines[1:]
formatted_contacts = []
seen_emails = set()
group_counts = {}
tag_counts = {}
duplicate_emails_skipped = 0

tag_aliases = contact_rules["tag_aliases"]
city_groups = contact_rules["city_groups"]

for row in rows:
  name_text, email_text, tags_text, city_text = row.split(",")

  clean_name = " ".join(name_text.strip().split())
  clean_email = email_text.strip().lower()
  clean_city = " ".join(city_text.strip().split())

  if clean_email in seen_emails:
      duplicate_emails_skipped += 1
      continue

  seen_emails.add(clean_email)
  clean_tags = []

  for raw_tag in tags_text.split(";"):
      clean_tag = raw_tag.strip().lower()
      if clean_tag == "":
          continue

      mapped_tag = tag_aliases.get(clean_tag, clean_tag)
      if mapped_tag not in clean_tags:
          clean_tags.append(mapped_tag)
          if mapped_tag not in tag_counts:
              tag_counts[mapped_tag] = 0
          tag_counts[mapped_tag] += 1

  group = city_groups.get(clean_city.lower(), "general")
  if group not in group_counts:
      group_counts[group] = 0
  group_counts[group] += 1

  formatted_contacts.append(
      {
          "name": clean_name,
          "email": clean_email,
          "city": clean_city,
          "group": group,
          "tags": clean_tags,
      }
  )

contact_summary = {
  "total_rows": len(rows),
  "formatted_count": len(formatted_contacts),
  "duplicate_emails_skipped": duplicate_emails_skipped,
  "group_counts": group_counts,
  "tag_counts": tag_counts,
}

print("Formatted contacts:", formatted_contacts)
print("Contact summary:", contact_summary)
高级技巧
想更进一步?点击展开

这节课最重要的收获是:你已经能把读取记录、清字段、去重、套规则、做结构化结果这些动作,连成一条别人真的能接住的工作流。

当你能把一份原本混乱的联系人表整理成可交付名单时,这一整套数据与文本处理能力就已经真正长在你手里了。

Loading...
终端输出
Terminal
Ready to run...