在Python数据处理工作中,我们经常会遇到形如“15.3kg”“-2.5米”“3.2 h”这样的字符串,它们由数值和单位拼接而成。如果直接调用float函数,解释器会抛出ValueError,因为字母和空格不在浮点语法范围内。要正确转换为浮点数,核心思路是先分离数值与单位,再根据业务规则决定单位是否参与换算。

为什么不能直接转换
Python内置的float函数只接受纯数字字符串,可选地包含正负号、小数点和科学计数法。一旦字符串里混杂了非数字字符,解析就会失败。很多初学者以为写个try except就行,但那样只是跳过错误,并没有真正拿到可用的数值。
举个例子,从设备日志读出的温度是“36.5℃”,如果只捕获异常而不处理,温度字段就丢失了。正确做法是在转换前把数值抠出来,单位要么丢弃,要么换算成标准量纲。下面用正则演示最基础的处理方式。
import re
def extract_number(text):
match = re.search(r'-?d+(.d+)?', text)
if match:
return float(match.group())
return None
print(extract_number('36.5℃')) # 36.5
print(extract_number('-2.5米')) # -2.5
print(extract_number('无数据')) # None
带单位换算的处理方案
如果业务要求统一单位,例如全部转为克、秒或米,就需要建立单位到系数的映射。这样不仅能提取数值,还能自动放大或缩小。相比硬编码判断,字典查表更清晰,也方便后期扩展新单位。
下面示例支持千克与克、小时与分钟的转换。注意正则里把单位也捕获了,再通过字典拿到倍数。若遇到未定义单位,返回None并提示,避免静默出错。
import re
unit_factor = {
'kg': 1000, 'g': 1,
'h': 3600, 'min': 60, 's': 1
}
def to_standard(text):
match = re.search(r'(-?d+(?:.d+)?)s*([a-zA-Z]+)', text)
if not match:
return None
num = float(match.group(1))
unit = match.group(2)
if unit not in unit_factor:
raise ValueError('未知单位: ' + unit)
return num * unit_factor[unit]
print(to_standard('2.5kg')) # 2500.0
print(to_standard('1.5 h')) # 5400.0
处理空格与全角字符
真实文本常带有不规则空格,甚至中文全角括号、全角字母。上面的正则用了s*已经能吃掉半角空格,但全角字符需要额外归一化。可以先用str.replace把全角空格转半角,或用unidecode类库。另外,单位可能是中文“千克”,这时要把键也写成中文。
下面代码演示了兼容中文单位的简单写法,并去除了全角空格。这样从Excel复制来的“12.0 千克”也能稳定转换。
import re
def clean_text(s):
return s.replace(' ', ' ').replace('千克', 'kg').replace('米', 'm')
def parse_cn(text):
text = clean_text(text)
match = re.search(r'(-?d+(?:.d+)?)s*([a-zA-Z]+)', text)
if not match:
return None
return float(match.group(1))
print(parse_cn('12.0 千克')) # 12.0
print(parse_cn('3.5m')) # 3.5
使用pandas批量转换
当数据落在DataFrame列里,可以用apply结合前面的函数,一行代码清洗整列。相比循环写起来更短,也利于链式处理。要注意原始列可能含空值,函数里已返回None,pandas会存成NaN,后续可用fillna填补。
以下示例读取一个带单位的重量列,转成标准克数,并新增一列。实际项目中可把单位映射表抽成配置文件,方便运营人员维护。
import pandas as pd
unit_factor = {'kg': 1000, 'g': 1}
def col_to_gram(text):
if pd.isna(text):
return None
match = re.search(r'(-?d+(?:.d+)?)s*([a-zA-Z]+)', str(text))
if not match:
return None
num = float(match.group(1))
unit = match.group(2)
return num * unit_factor.get(unit, 1)
df = pd.DataFrame({'重量': ['1.2kg', '300g', '0.5kg']})
df['克数'] = df['重量'].apply(col_to_gram)
print(df)
常见误区与建议
一个典型误区是用字符串切片假定单位固定长度,比如text[:-2]。这种做法在单位变长或前面有空格时立刻失效。正则或split才是稳妥选择。另一个误区是忽略负数与科学计数法,正则应至少支持负号和小数点。
建议把单位换算逻辑封装成独立模块,并写单元测试覆盖“无单位”“带空格”“未知单位”等分支。这样数据格式变更时,只需改映射表,不必动业务代码,降低维护成本。