Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Convert camel-case to snake-case in python.
#!/usr/bin/env python
"""
Convert camel-case to snake-case in python.
e.g.: CamelCase -> snake_case
Relevant StackOverflow question: http://stackoverflow.com/a/1176023/293064
"""
__author__ = 'Jay Taylor [@jtaylor]'
import re
_underscorer1 = re.compile(r'(.)([A-Z][a-z]+)')
_underscorer2 = re.compile('([a-z0-9])([A-Z])')
def camelToSnake(s):
"""
Is it ironic that this function is written in camel case, yet it
converts to snake case? hmm..
"""
subbed = _underscorer1.sub(r'\1_\2', s)
return _underscorer2.sub(r'\1_\2', subbed).lower()
if __name__ == '__main__':
assert camelToSnake('snakesOnAPlane') == 'snakes_on_a_plane'
assert camelToSnake('SnakesOnAPlane') == 'snakes_on_a_plane'
assert camelToSnake('snakes_on_a_plane') == 'snakes_on_a_plane'
assert camelToSnake('IPhoneHysteria') == 'i_phone_hysteria'
assert camelToSnake('iPhoneHysteria') == 'i_phone_hysteria'
print 'All tests passed.'
@burnsjeremy

This comment has been minimized.

Copy link

burnsjeremy commented Jul 4, 2013

This is great! Thanks!

@EdgeCaseBerg

This comment has been minimized.

Copy link

EdgeCaseBerg commented Aug 14, 2013

Really useful! Thanks a bunch!

@yahyaKacem

This comment has been minimized.

Copy link

yahyaKacem commented Dec 29, 2013

That did inspire me to do this.
Check it out I found a small bugs in this, and I made it into a class.

@ramast

This comment has been minimized.

Copy link

ramast commented Jan 29, 2016

Thanks for the code, I love the idea.
I've wrote a simplified version based on it

def camel_to_snake(s):
    return re.sub("([A-Z])", "_\\1", s).lower().lstrip("_")

The simplified version works perfectly fine unless you provided string that starts with _
i.e. camel_to_snake("__IPhone") will return "i_phone" instead of __i_phone

@abozhilov

This comment has been minimized.

Copy link

abozhilov commented Nov 29, 2017

You can use single regex with negative lookahead/lookbehid they are zero length assertions.

import re


_reg = re.compile(r'(?!^)(?<!_)([A-Z])')

def camelToSnake(s):
    """ 
    Is it ironic that this function is written in camel case, yet it
    converts to snake case? hmm..
    """
    return _reg.sub(r'_\1', s).lower()

if __name__ == '__main__':
    assert camelToSnake('snakesOnAPlane') == 'snakes_on_a_plane'
    assert camelToSnake('SnakesOnAPlane') == 'snakes_on_a_plane'
    assert camelToSnake('snakes_on_a_plane') == 'snakes_on_a_plane'
    assert camelToSnake('IPhoneHysteria') == 'i_phone_hysteria'
    assert camelToSnake('iPhoneHysteria') == 'i_phone_hysteria'
    assert camelToSnake("__IPhone") == '__i_phone'
    print 'All tests passed.'
@AHLinJie

This comment has been minimized.

Copy link

AHLinJie commented Jan 19, 2018

un = json.loads(json.dumps(profile), object_hook=camel_to_snake)

@Kai-Chen

This comment has been minimized.

Copy link

Kai-Chen commented Feb 9, 2018

The lookaround solution is incomplete:

>>> camelToSnake('HTTPResponseCodeXYZ')
'h_t_t_p_response_code_x_y_z'
@dopstar

This comment has been minimized.

Copy link

dopstar commented Sep 29, 2019

The lookaround solution is incomplete:
>>> camelToSnake('HTTPResponseCodeXYZ')
'h_t_t_p_response_code_x_y_z'

I guess its intended since the tests are doing this

assert camelToSnake('IPhoneHysteria') == 'i_phone_hysteria'

instead of this

assert camelToSnake('IPhoneHysteria') == 'iphone_hysteria'

you can use the inflection library (see https://github.com/jpvanhal/inflection/blob/master/inflection.py#L395-L414) or this snippet taken from their code

>>> regex1 = re.compile(r'([A-Z]+)([A-Z][a-z])')
>>> regex2 = re.compile(r'([a-z\d])([A-Z])')
>>> text = 'HTTPResponseCodeXYZ'
>>> regex2.sub(r'\1_\2', regex1.sub(r'\1_\2', text)).lower()
'http_response_code_xyz'
>>> 
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.