{"id":15697335,"url":"https://github.com/joellefkowitz/convert-case","last_synced_at":"2025-04-30T22:23:00.612Z","repository":{"id":62564727,"uuid":"404858074","full_name":"JoelLefkowitz/convert-case","owner":"JoelLefkowitz","description":"Convert between string cases with built-in case inference.","archived":false,"fork":false,"pushed_at":"2024-05-27T22:07:23.000Z","size":249,"stargazers_count":6,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-08T18:53:26.064Z","etag":null,"topics":["camel","case","convert","kebab","snake"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JoelLefkowitz.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-09-09T20:16:25.000Z","updated_at":"2024-05-27T22:51:05.000Z","dependencies_parsed_at":"2024-10-24T02:53:19.728Z","dependency_job_id":"e4072f69-0c05-4db9-91c8-2e30f974b8cd","html_url":"https://github.com/JoelLefkowitz/convert-case","commit_stats":{"total_commits":20,"total_committers":1,"mean_commits":20.0,"dds":0.0,"last_synced_commit":"f22b359a28dc9634e71486c5c6cc51febc225757"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JoelLefkowitz%2Fconvert-case","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JoelLefkowitz%2Fconvert-case/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JoelLefkowitz%2Fconvert-case/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JoelLefkowitz%2Fconvert-case/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JoelLefkowitz","download_url":"https://codeload.github.com/JoelLefkowitz/convert-case/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251790274,"owners_count":21644196,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["camel","case","convert","kebab","snake"],"created_at":"2024-10-03T19:16:35.097Z","updated_at":"2025-04-30T22:23:00.591Z","avatar_url":"https://github.com/JoelLefkowitz.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Convert case\n\nConvert between string cases with built-in case inference.\n\n![Review](https://img.shields.io/github/actions/workflow/status/JoelLefkowitz/convert-case/review.yml)\n![Version](https://img.shields.io/pypi/v/convert-case)\n![Downloads](https://img.shields.io/pypi/dw/convert-case)\n![Quality](https://img.shields.io/codacy/grade/3b8afbb8327d424b9990741fd587d7c4)\n![Coverage](https://img.shields.io/codacy/coverage/3b8afbb8327d424b9990741fd587d7c4)\n\n## Installing\n\n```bash\npip install convert-case\n```\n\n## Documentation\n\nDocumentation and more detailed examples are hosted on [Github Pages](https://joellefkowitz.github.io/convert-case).\n\n## Usage\n\n```python\nfrom convert_case import camel_case\n\ncamel_case('camel case') # Inferred: lower -\u003e camel\n'camelCase'\n\ncamel_case('Camel Case') # Inferred: title -\u003e camel\n'camelCase'\n\ncamel_case('CamelCase') # Inferred: pascal -\u003e camel\n'camelCase'\n```\n\n### Exports\n\n```python\ndef pascal_case(string: str) -\u003e str:\n    ...\ndef is_pascal_case(string: str) -\u003e bool:\n    ...\n\ndef camel_case(string: str) -\u003e str:\n    ...\ndef is_camel_case(string: str) -\u003e bool:\n    ...\n\ndef kebab_case(string: str) -\u003e str:\n    ...\ndef is_kebab_case(string: str) -\u003e bool:\n    ...\n\ndef sentence_case(string: str) -\u003e str:\n    ...\ndef is_sentence_case(string: str) -\u003e bool:\n    ...\n\ndef snake_case(string: str) -\u003e str:\n    ...\ndef is_snake_case(string: str) -\u003e bool:\n    ...\n\ndef title_case(string: str) -\u003e str:\n    ...\ndef is_title_case(string: str) -\u003e bool:\n    ...\n\ndef upper_case(string: str) -\u003e str:\n    ...\ndef is_upper_case(string: str) -\u003e bool:\n    ...\n```\n\n### Definitions\n\n```python\nLOWER = re.compile(r\"^[a-z0-9\\s]*$\")\nUPPER = re.compile(r\"^[A-Z0-9\\s]*$\")\n\nTITLE = re.compile(r\"^(([A-Z0-9][a-z0-9]*)(\\s[A-Z0-9][a-z0-9]*)*)?$\")\nSENTENCE = re.compile(r\"^(([A-Z0-9][a-z0-9]*)(\\s[a-z0-9]*)*)?$\")\n\nCAMEL = re.compile(r\"^([a-z0-9][a-zA-Z0-9]*)?$\")\nPASCAL = re.compile(r\"^([A-Z0-9]|([A-Z0-9][a-z0-9]+)*)?$\")\n\nSNAKE = re.compile(r\"^([a-z0-9]+(_[a-z0-9]+)*)?$\")\nKEBAB = re.compile(r\"^([a-z0-9]+(-[a-z0-9]+)*)?$\")\n```\n\n### Test cases\n\n| test     | lower    | upper    | sentence | title    | camel  | snake    | kebab    | pascal |\n| -------- | -------- | -------- | -------- | -------- | ------ | -------- | -------- | ------ |\n| a        | a        | A        | A        | A        | a      | a        | a        | A      |\n| A        | a        | A        | A        | A        | a      | a        | a        | A      |\n| abc      | abc      | ABC      | Abc      | Abc      | abc    | abc      | abc      | Abc    |\n| ab cd    | ab cd    | AB CD    | Ab cd    | Ab Cd    | abCd   | ab_cd    | ab-cd    | AbCd   |\n| Ab cd    | ab cd    | AB CD    | Ab cd    | Ab Cd    | abCd   | ab_cd    | ab-cd    | AbCd   |\n| Ab Cd    | ab cd    | AB CD    | Ab cd    | Ab Cd    | abCd   | ab_cd    | ab-cd    | AbCd   |\n| ab_cd    | ab cd    | AB CD    | Ab cd    | Ab Cd    | abCd   | ab_cd    | ab-cd    | AbCd   |\n| ab-cd    | ab cd    | AB CD    | Ab cd    | Ab Cd    | abCd   | ab_cd    | ab-cd    | AbCd   |\n| abCd     | ab cd    | AB CD    | Ab cd    | Ab Cd    | abCd   | ab_cd    | ab-cd    | AbCd   |\n| ABCD     | abcd     | ABCD     | Abcd     | Abcd     | abcd   | abcd     | abcd     | Abcd   |\n| AbCd     | ab cd    | AB CD    | Ab cd    | Ab Cd    | abCd   | ab_cd    | ab-cd    | AbCd   |\n| ab cd ef | ab cd ef | AB CD EF | Ab cd ef | Ab Cd Ef | abCdEf | ab_cd_ef | ab-cd-ef | AbCdEf |\n| AbCdEf   | ab cd ef | AB CD EF | Ab cd ef | Ab Cd Ef | abCdEf | ab_cd_ef | ab-cd-ef | AbCdEf |\n| ab-cd-ef | ab cd ef | AB CD EF | Ab cd ef | Ab Cd Ef | abCdEf | ab_cd_ef | ab-cd-ef | AbCdEf |\n| Ab cd ef | ab cd ef | AB CD EF | Ab cd ef | Ab Cd Ef | abCdEf | ab_cd_ef | ab-cd-ef | AbCdEf |\n\n#### Numbers\n\nNumbers are treated as letters with no specific case.\n\n| test | lower | upper | sentence | title | camel | snake | kebab | pascal |\n| ---- | ----- | ----- | -------- | ----- | ----- | ----- | ----- | ------ |\n| 1    | 1     | 1     | 1        | 1     | 1     | 1     | 1     | 1      |\n| 1bc  | 1bc   | 1BC   | 1bc      | 1bc   | 1bc   | 1bc   | 1bc   | 1bc    |\n| a1c  | a1c   | A1C   | A1c      | A1c   | a1c   | a1c   | a1c   | A1c    |\n| ab1  | ab1   | AB1   | Ab1      | Ab1   | ab1   | ab1   | ab1   | Ab1    |\n| a1 c | a1 c  | A1 C  | A1 c     | A1 C  | a1C   | a1_c  | a1-c  | A1C    |\n| a1-c | a1 c  | A1 C  | A1 c     | A1 C  | a1C   | a1_c  | a1-c  | A1C    |\n\n## Discussion\n\nA goal of this converter is that it is deterministic. If we consider the following examples we can see that this is not simple to achieve. How should we interpret the string 'ABC', is it in upper case or pascal case?\n\n| test  | upper | pascal |\n| ----- | ----- | ------ |\n| abc   | ABC   | Abc    |\n| a b c | A B C | ABC    |\n\nOur options are:\n\n- To consider strings with consecutive capitals like 'ABC' not to be pascal case. If in this case 'a b c' is parsed to 'Abc' it would clash with parsing 'abc' into pascal case.\n\n- To store some state that remembers the string's case before parsing. This would introduce too much complexity.\n\n- To prioritize parsing the string as one case unless told otherwise. We choose to pick upper case as the inferred case. The caveat here is that we will no longer be performing 'round trip' conversion.\n\nRound trip conversion:\n\n```python\nkebab_case('a b c')\n'a-b-c'\n\nlower_case('a-b-c')\n'a b c'\n```\n\nNot round trip conversion:\n\n```python\npascal_case('a b c')\n'ABC'\n\nlower_case('ABC')\n'abc'\n```\n\n## Tooling\n\n### Dependencies\n\nTo install dependencies:\n\n```bash\nyarn install\npip install .[all]\n```\n\n### Tests\n\nTo run tests:\n\n```bash\nthx test\n```\n\n### Documentation\n\nTo generate the documentation locally:\n\n```bash\nthx docs\n```\n\n### Linters\n\nTo run linters:\n\n```bash\nthx lint\n```\n\n### Formatters\n\nTo run formatters:\n\n```bash\nthx format\n```\n\n## Contributing\n\nPlease read this repository's [Code of Conduct](CODE_OF_CONDUCT.md) which outlines our collaboration standards and the [Changelog](CHANGELOG.md) for details on breaking changes that have been made.\n\nThis repository adheres to semantic versioning standards. For more information on semantic versioning visit [SemVer](https://semver.org).\n\nBump2version is used to version and tag changes. For example:\n\n```bash\nbump2version patch\n```\n\n### Contributors\n\n- [Joel Lefkowitz](https://github.com/joellefkowitz) - Initial work\n\n## Remarks\n\nLots of love to the open source community!\n\n\u003cdiv align='center'\u003e\n    \u003cimg width=200 height=200 src='https://media.giphy.com/media/osAcIGTSyeovPq6Xph/giphy.gif' alt='Be kind to your mind' /\u003e\n    \u003cimg width=200 height=200 src='https://media.giphy.com/media/KEAAbQ5clGWJwuJuZB/giphy.gif' alt='Love each other' /\u003e\n    \u003cimg width=200 height=200 src='https://media.giphy.com/media/WRWykrFkxJA6JJuTvc/giphy.gif' alt=\"It's ok to have a bad day\" /\u003e\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoellefkowitz%2Fconvert-case","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoellefkowitz%2Fconvert-case","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoellefkowitz%2Fconvert-case/lists"}