在使用Pandas进行数据处理时,经常需要将DataFrame输出为CSV文件,部分业务场景要求CSV中的字段内容保持固定字符长度,并且实现左对齐、右对齐或者居中对齐的显示效果,避免内容长短不一影响后续使用。

为什么默认导出无法满足需求
Pandas的to_csv方法默认按照数据的原始内容导出,不会做字符长度限制和对齐处理。比如一个姓名字段,有的内容是2个汉字,有的是3个汉字,导出的CSV中对应列的宽度会随内容变化,无法保证固定长度,也不存在对齐规则。
方案一:导出前预处理DataFrame数据
这种方案的核心思路是,在调用to_csv之前,先对DataFrame的每个字段做格式化处理,将内容填充到固定长度,再导出CSV。这里需要用到Python的字符串格式化方法,结合Pandas的applymap或者逐列处理的方式实现。
实现步骤
- 确定每个字段的目标固定长度,以及对应的对齐方式
- 编写格式化函数,根据对齐方式将字符串填充到指定长度
- 对DataFrame的所有字段应用格式化函数
- 调用
to_csv导出处理后的DataFrame
完整代码示例
下面的示例假设要对姓名、年龄、城市三个字段做处理,姓名固定6个字符左对齐,年龄固定3个字符右对齐,城市固定8个字符居中对齐:
import pandas as pd
# 构造测试DataFrame
data = {
"姓名": ["张三", "李四", "王五五"],
"年龄": [20, 25, 30],
"城市": ["北京", "上海", "广州"]
}
df = pd.DataFrame(data)
def format_str(value, length, align="left"):
"""
格式化字符串到固定长度
:param value: 原始值
:param length: 目标固定长度
:param align: 对齐方式 left/right/center
:return: 格式化后的字符串
"""
value_str = str(value)
if align == "left":
# 左对齐,右侧用空格填充
return value_str.ljust(length)
elif align == "right":
# 右对齐,左侧用空格填充
return value_str.rjust(length)
elif align == "center":
# 居中对齐,两侧用空格填充
return value_str.center(length)
return value_str
# 对每个字段做格式化处理
df["姓名"] = df["姓名"].apply(lambda x: format_str(x, 6, "left"))
df["年龄"] = df["年龄"].apply(lambda x: format_str(x, 3, "right"))
df["城市"] = df["城市"].apply(lambda x: format_str(x, 8, "center"))
# 导出CSV,不保留索引
df.to_csv("formatted_data.csv", index=False, encoding="utf-8-sig")
运行上述代码后,导出的CSV中每个字段都会保持固定的字符长度,并且按照设定的对齐方式显示。注意这里使用utf-8-sig编码,避免Windows下打开CSV出现中文乱码问题。
方案二:自定义CSV写入逻辑
如果需要在导出时动态控制每个字段的长度和对齐规则,也可以不使用to_csv方法,而是自定义CSV的写入逻辑,逐行处理DataFrame的内容后写入文件。
实现步骤
- 定义每个字段的长度和对齐规则配置
- 打开CSV文件,写入表头
- 遍历DataFrame的每一行,对每个字段做格式化处理
- 将格式化后的行内容写入CSV文件
完整代码示例
import pandas as pd
import csv
# 构造测试DataFrame
data = {
"姓名": ["张三", "李四", "王五五"],
"年龄": [20, 25, 30],
"城市": ["北京", "上海", "广州"]
}
df = pd.DataFrame(data)
# 字段配置:字段名 -> (固定长度, 对齐方式)
field_config = {
"姓名": (6, "left"),
"年龄": (3, "right"),
"城市": (8, "center")
}
def format_value(value, length, align):
"""格式化单个值到固定长度"""
value_str = str(value)
if align == "left":
return value_str.ljust(length)
elif align == "right":
return value_str.rjust(length)
elif align == "center":
return value_str.center(length)
return value_str
# 自定义写入CSV
with open("custom_formatted.csv", "w", encoding="utf-8-sig", newline="") as f:
writer = csv.writer(f)
# 写入表头
writer.writerow(field_config.keys())
# 遍历每一行数据
for _, row in df.iterrows():
formatted_row = []
for field, (length, align) in field_config.items():
formatted_value = format_value(row[field], length, align)
formatted_row.append(formatted_value)
writer.writerow(formatted_row)
这种方案的优势是可以更灵活地控制写入逻辑,比如可以在写入时添加额外的校验规则,或者处理特殊字段的格式化需求,不需要提前修改原始DataFrame的内容。
两种方案的选择建议
如果只需要一次性导出固定长度对齐的CSV,并且后续不需要使用原始DataFrame,优先选择方案一,代码更简洁,实现更快。如果需要在导出过程中做更多自定义处理,或者需要保留原始DataFrame的内容不被修改,优先选择方案二,灵活性更高。
需要注意,如果字段内容本身的长度超过设定的固定长度,上述示例中的格式化函数会直接返回原始内容,不会截断。如果有截断需求,可以在格式化函数中先判断内容长度,超过的部分做截取处理即可。