fluttersmith/py-snippetsGitHub ↗

Convert between naming cases

Convert text between snake_case, kebab-case, camelCase and PascalCase, acronyms included.

Strings#text#conversionO(n) time✓ 7 examples pass on 3.11–3.14

One word splitter, four joins. The hard part is splitting parseHTTPResponse into parse, HTTP, Response.

naming_cases.py✓ ruff · mypy --strict
import re

_WORD = re.compile(r"[A-Z]+(?=[A-Z][a-z]|\b|_|\d)|[A-Z]?[a-z]+|[A-Z]+|\d+")


def split_words(text: str) -> list[str]:
    """Split ``text`` into words at spaces, ``-``, ``_`` and case changes."""
    return _WORD.findall(text)


def to_snake(text: str) -> str:
    """Convert ``text`` to snake_case."""
    return "_".join(word.lower() for word in split_words(text))


def to_kebab(text: str) -> str:
    """Convert ``text`` to kebab-case."""
    return "-".join(word.lower() for word in split_words(text))


def to_camel(text: str) -> str:
    """Convert ``text`` to camelCase."""
    pascal = to_pascal(text)
    return pascal[:1].lower() + pascal[1:]


def to_pascal(text: str) -> str:
    """Convert ``text`` to PascalCase."""
    return "".join(word.capitalize() for word in split_words(text))
  1. an acronym, a capitalised word, a lowercase run, or digits
examples✓ 7 doctests · 3.11–3.14
passed on Python 3.11 to 3.14: >>> split_words("parseHTTPResponse_v2 and-more")['parse', 'HTTP', 'Response', 'v', '2', 'and', 'more']passed on Python 3.11 to 3.14: >>> to_snake("AllThe-small Things")'all_the_small_things'passed on Python 3.11 to 3.14: >>> to_snake("parseHTTPResponse")'parse_http_response'passed on Python 3.11 to 3.14: >>> to_kebab("some-mixed_string With spaces")'some-mixed-string-with-spaces'passed on Python 3.11 to 3.14: >>> to_camel("some_database_field_name")'someDatabaseFieldName'passed on Python 3.11 to 3.14: >>> to_camel("")''passed on Python 3.11 to 3.14: >>> to_pascal("some label that needs pascal")'SomeLabelThatNeedsPascal'
Edit the function or the examples and run the doctests here, on Python 3.14. Python loads only when you click (about 7 MB, cached after the first time).

How it works

  • The regex matches, in order: an acronym followed by a capitalised word, a capitalised or lowercase word, a run of capitals, or digits.
  • Spaces, hyphens and underscores are never part of a match, so they act as separators.
  • Each case function only lowercases or capitalises the words and joins them.
  • Single-letter words don’t survive a round trip: to_pascal('a_b') is AB, which then reads as one acronym.

Complexity: O(n) time, O(n) space

Importfrom pysnippets.strings.naming_cases import split_words, to_snake, to_kebab, to_camel, to_pascalNo dependencies: copy naming_cases.py into your project, or clone the repo.

Adapted from camel, kebab and snake in 30-seconds-of-python by the 30 seconds of code contributors, CC BY 4.0. Changed: Merged three snippets around one shared word splitter; added PascalCase; typed. Suggest an edit.