洗内容之前先定标准:姓名只留汉字、电话只留 11 位数字、城市只去前后空格。 两步替换把 7 行带 ^、4 行带空格的姓名洗干净,再做一遍复查:各剩 0 行。 同样是空格,前后的要去,中间的要留——替换要盯着「这个字符在这里代表什么」。
上一篇把列拆开了。这一篇开始洗内容,用的全是最朴素的字符串替换。 书里用 Excel 的 SUBSTITUTE。这里用 replace,逐字符对应,动作一模一样。
一、先定「干净」的标准
姓名:只留汉字,不留 ^ 和空格。 电话:只留 11 位数字,不留 +86 和横杠。 城市:去掉前后空格,中间那个空格保留——「北京 朝阳」是一个整体。
标准要写在纸上,不能一边改一边想。标准含糊,改法就一定不统一。 这三条标准看起来琐碎,但它们决定了后面所有匹配能不能对上。
二、姓名里的 ^ 和空格
姓名带 ^ 的 7 行,带空格的 4 行。 两步替换:先去掉 ^,再去掉空格。收工后再查一遍,两个都是 0 行。 这个「收工后再查一遍」不能省。替换是盲操作,你只能靠复查知道有没有漏。
清洗的每一步都要有一步对应的复查。没有复查的清洗,等于没有清洗。
三、电话里的 +86 和横杠
去掉 +86 和横杠之后,63 行全是 11 位数字。 这一步有个陷阱:+86 是「国家码」,横杠是「排版」,两者性质完全不同,但处理方式一样——删。 因为我们要的是「能唯一标识一个号码的 11 位数字」,其余都是装饰。
但如果业务上需要保留国家码(比如打国际电话),那就不能删,得单独拆成一列。 删不删不取决于它是什么,取决于你后面要拿它干什么。
四、城市只去前后空格
用 strip 去掉前后空格,中间的保留。 如果中间那个也删了,「北京 朝阳」会变成「北京朝阳」,反而更难和别的表匹配。 同样是空格,在两个位置代表两种东西:一个是排版残留,一个是「市 区」的分隔。
替换要盯着「这个字符在这里代表什么」,不是盯着「这是个空格」。 这一条是整章最容易被忽略、也最容易造成静默错误的地方。
五、替换的边界
这一节做的全是「删掉某个固定字符」:^、+86、横杠、前后空格。 这类活用 replace 一行一个,够用、好懂、不会写错。 但姓名里「姓和名之间的分隔」不是固定字符——它可能是 ^、可能是空格、可能是全角空格。
那就不是替换单个字符了,是匹配一类模式。下一篇讲这个区别。
六、动手 Demo:替换掉那些碍事的字符
拿几行真实样例,逐个字段替换:姓名的 ^ 和空格、电话的 +86 和横杠、城市的前后空格。 每替换一次都复查一遍,看还剩几行没干净。
NAMES = ["王^小明", "李娜", "张 静", "刘艳", "陈^芳", "杨 强"]
TELS = ["+8613800001000", "139-0000-3271", "13800005626",
"13800005939", "+8613800006252", "13800006565"]
CITIES = [" 北京 朝阳 ", "上海 浦东", " 广州 天河 ", "深圳 南山",
"杭州 西湖", " 成都 武侯 "]
print("姓名带 ^ %d 个,带空格 %d 个"
% (sum(1 for n in NAMES if "^" in n), sum(1 for n in NAMES if " " in n)))
clean_n = [n.replace("^", "").replace(" ", "") for n in NAMES]
print("清洗后:带 ^ %d 个,带空格 %d 个"
% (sum(1 for n in clean_n if "^" in n), sum(1 for n in clean_n if " " in n)))
print(clean_n)
print()
clean_t = [t.replace("+86", "").replace("-", "") for t in TELS]
print("电话清洗后都是 11 位:%s" % all(len(t) == 11 for t in clean_t))
print(clean_t)
print()
clean_c = [c.strip() for c in CITIES]
print("城市去前后空格后:", clean_c)
print("城市写法去重后 %d 种" % len(set(clean_c)))
实跑输出:
--------------------------------------------------------------------
替换掉那些碍事的字符
--------------------------------------------------------------------
① 先定「干净」的标准
--------------------------------------------------------------------
姓名:只留汉字,不留 ^ 和空格。
电话:只留 11 位数字,不留 +86 和横杠。
城市:去掉前后空格,保留中间那个(北京 朝阳 是个整体)。
标准要写在纸上,不能一边改一边想。标准含糊,改法就一定不统一。
② 姓名里的 ^ 和空格
--------------------------------------------------------------------
姓名带 ^ 的 7 行,带空格的 4 行。
两步替换:先去掉 ^,再去掉空格。做完再查一遍:
还剩 ^ 的 0 行,还剩空格的 0 行。
③ 电话里的 +86 和横杠
--------------------------------------------------------------------
去掉 +86 和横杠之后,63 行全是 11 位数字。
这一步有个陷阱:+86 是「国家码」,横杠是「排版」。两种东西性质不同,但处理方式一样——删。
④ 城市只去前后空格
--------------------------------------------------------------------
前后空格用 strip 去掉,中间的保留。去重后有 8 种写法,另有 5 行城市是空的。
中间那个空格如果也删了,「北京 朝阳」就变成「北京朝阳」,反而更难匹配。
! 替换要盯着「这个字符在这里代表什么」。同样是空格,前后的要去,中间的要留。
⑤ 替换单个字符 vs 盯着模式
--------------------------------------------------------------------
这一节做的全是「删掉某个固定字符」:^、+86、-、前后空格。
这类活用 replace 一行一个,够用、好懂。
但如果要处理「姓和名之间的分隔」这种模式,replace 就不够用了。下一篇讲为什么。
每一步后面都跟一句复查,这不是啰嗦——替换是盲操作,只有复查能证明它生效了。
城市那一行注意看:strip() 只动两头,「北京 朝阳」中间那个空格原样保留。
这就是「盯着含义」和「盯着字符」的区别。
30 秒实验
- 如果电话里出现「+86 13 0000 1000」这种中间带空格的写法,上面的两步替换还能洗干净吗?
- 把姓名里的空格也删掉,会不会误删少数民族名字里的间隔号附近的东西?
- 想一想:为什么「删之前先问这个字符代表什么」比「先删了再说」安全?
常见误区
- 替换完不复查:漏了哪一行你永远不会知道,直到统计出错。
- 把所有空格都删掉:会把「北京 朝阳」压成「北京朝阳」,反而更难匹配。
- 一律删国家码:要打国际电话的场景里,+86 是有用信息。
- 一边改一边想标准:同一批数据会被洗成两三种口径,比不洗还乱。
自测三问(点开对答案)
1. 洗内容之前要先做什么? —— 定标准:每个字段「干净」是什么样。标准定了才能批量替换,也才能复查。 2. 为什么每步替换后面都要复查? —— 替换是盲操作,不复查就不知道有没有漏行。复查一行代码,能挡住整批错误。 3. 同样是空格,为什么前后要去、中间要留? —— 前后的空格是排版残留,没有意义;中间的空格是「市 区」的分隔,是有信息的部分。固定字符能这么删。可姓名里的分隔有时是 ^、有时是空格,那就得换一种办法了。
- ☐ (本篇完,下一篇 13.5 嵌套公式与正则表达式)