Normalize CSV Column Names to snake_case in Python

Convert CSV header names to snake_case using a regular expression and write the updated file in place.

Easy Python 3.9+ Aug 9, 2026 Files & data 13 views 0 copies

Python code

32 lines
Python 3.9+
import csv
import re
import sys


def to_snake_case(header):
    header = re.sub(r"(?<=[a-z0-9])(?=[A-Z])", "_", header)
    header = re.sub(r"[^a-zA-Z0-9]+", "_", header).strip("_").lower()
    return header


def normalize_csv_headers(input_path, output_path=None):
    with open(input_path, newline="", encoding="utf-8") as f:
        reader = csv.reader(f)
        rows = list(reader)

    if not rows:
        return

    normalized = [to_snake_case(col) for col in rows[0]]
    rows[0] = normalized

    output = output_path or input_path
    with open(output, "w", newline="", encoding="utf-8") as f:
        writer = csv.writer(f)
        writer.writerows(rows)

    print("Normalized headers:", normalized)


if __name__ == "__main__":
    normalize_csv_headers("example.csv")

Output

stdout
Normalized headers: ['id', 'first_name', 'last_name', 'email', 'created_at']

How it works

The to_snake_case function uses two regex substitutions. The first inserts an underscore between a lowercase letter/digit and an uppercase letter to handle camelCase. The second replaces any sequence of non-alphanumeric characters with an underscore, then strips leading/trailing underscores and lowercases everything. Reading the entire file into a list of rows with csv.reader allows easy header mutation before writing back. Writing to the same path overwrites the original file, and printing the normalized list confirms the change.

Common mistakes

  • Forgetting to strip underscores after substitution, leaving headers like '_first_name_'.
  • Not handling files with no header row, causing the function to silently skip or error.
  • Assuming all headers are simple ASCII; accented characters get stripped by the regex.

Variations

  1. Use `csv.DictReader` and `csv.DictWriter` to convert headers while streaming rows.
  2. Write to a new file instead of overwriting to preserve the original.

Real-world use cases

  • Preparing messy CSV exports from legacy systems for ingestion into a database schema that enforces snake_case naming.
  • Normalizing column names from a user-uploaded CSV file before performing data analysis in pandas.
  • Standardizing headers across multiple CSV files before merging them into a single dataset.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Files & data

Related tutorials and quizzes for this topic.