Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion inflection/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ def transliterate(string: str) -> str:
return normalized.encode('ascii', 'ignore').decode('ascii')


def underscore(word: str) -> str:
def underscore(word: str, split_numbers: bool = False) -> str:
"""
Make an underscored, lowercase form from the expression in the string.

Expand All @@ -403,6 +403,14 @@ def underscore(word: str) -> str:
>>> underscore("DeviceType")
'device_type'

If ``split_numbers`` is ``True`` inserts underscores between
numbers and alphabet characters.

Example::

>>> underscore('xyz123', split_numbers=True)
'xyz_123'

As a rule of thumb you can think of :func:`underscore` as the inverse of
:func:`camelize`, though there are cases where that does not hold::

Expand All @@ -411,6 +419,9 @@ def underscore(word: str) -> str:

"""
word = re.sub(r"([A-Z]+)([A-Z][a-z])", r'\1_\2', word)
if split_numbers:
word = re.sub(r"([a-zA-Z])(\d)", r'\1_\2', word)
word = re.sub(r"(\d)([a-z])", r'\1_\2', word)
word = re.sub(r"([a-z\d])([A-Z])", r'\1_\2', word)
word = word.replace("-", "_")
return word.lower()
Expand Down
15 changes: 15 additions & 0 deletions test_inflection.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@
("HTML", "html"),
)

CAMEL_TO_UNDERSCORE_SPLITTING_NUMBERS = (
("xyz123", "xyz_123"),
("xyZ123", "xy_z_123"),
("xy123z", "xy_123_z"),
("xy123Z", "xy_123_z")
)

STRING_TO_PARAMETERIZED = (
(u"Donald E. Knuth", "donald-e-knuth"),
(
Expand Down Expand Up @@ -360,6 +367,14 @@ def test_underscore(camel, underscore):
assert underscore == inflection.underscore(camel)


@pytest.mark.parametrize(
("camel", "underscore"),
CAMEL_TO_UNDERSCORE_SPLITTING_NUMBERS
)
def test_underscore_split_numbers(camel, underscore):
assert underscore == inflection.underscore(camel, split_numbers=True)


@pytest.mark.parametrize(
("some_string", "parameterized_string"),
STRING_TO_PARAMETERIZED
Expand Down