tools/caseconversions.py

Tue, 01 Mar 2022 17:00:19 +0200

author
Teemu Piippo <teemu@hecknology.net>
date
Tue, 01 Mar 2022 17:00:19 +0200
changeset 149
008989bc7d6e
parent 41
0abada2a9802
permissions
-rw-r--r--

work on edit history

#!/usr/bin/env python
# coding: utf-8

'''
Provides facilities to converting identifier cases.
'''

#
#	Copyright 2015 Teemu Piippo
#	All rights reserved.
#
#	Redistribution and use in source and binary forms, with or without
#	modification, are permitted provided that the following conditions
#	are met:
#
#	1. Redistributions of source code must retain the above copyright
#	   notice, this list of conditions and the following disclaimer.
#	2. Redistributions in binary form must reproduce the above copyright
#	   notice, this list of conditions and the following disclaimer in the
#	   documentation and/or other materials provided with the distribution.
#	3. Neither the name of the copyright holder nor the names of its
#	   contributors may be used to endorse or promote products derived from
#	   this software without specific prior written permission.
#
#	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
#	"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
#	TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
#	PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
#	OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
#	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#	PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
#	PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
#	LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
#	NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#	SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#

import string
import re

def to_one_case (name, tolower):
	'''
	Convers name to either all uppercase or all lowercase (depending on the truth value of tolower), using underscores
	as delimiters.
	'''
	result = ""
	targetSet = (string.ascii_lowercase if tolower else string.ascii_uppercase) + string.digits
	inverseSet = (string.ascii_uppercase if tolower else string.ascii_lowercase)
	isUnderscorable = lambda ch: ch in string.ascii_uppercase \
		or ch in string.whitespace or ch in string.punctuation
	previousWasUnderscorable = isUnderscorable (name[0])

	for ch in name:
		if isUnderscorable (ch) and result != "" and not previousWasUnderscorable:
			result += "_"

		if ch in inverseSet:
			result += (ch.lower() if tolower else ch.upper())
		elif ch in targetSet:
			result += ch
		previousWasUnderscorable = isUnderscorable (ch)

	return result

def to_camel_case (name, java = False):
	'''
	Converts name to camelcase. If java is False, the first letter will be lowercase, otherwise it will be uppercase.
	'''
	result = ""
	wantUpperCase = False

	# If it's all uppercase, make it all lowercase so that this algorithm can digest it
	if name == name.upper():
		name = name.lower()

	for ch in name:
		if ch == '_':
			wantUpperCase = True
			continue

		if wantUpperCase:
			if ch in string.ascii_lowercase:
				ch = ch.upper()
			wantUpperCase = False

		result += ch

	if java:
		match = re.match (r'^([A-Z]+)([A-Z].+)$', result)
		if match:
			result = match.group (1).lower() + match.group (2)
		else:
			result = result[0].lower() + result[1:]
	else:
		result = result[0].upper() + result[1:]
	return result

case_styles = {
	'lower': lambda name: to_one_case (name, tolower=True),
	'upper': lambda name: to_one_case (name, tolower=False),
	'camel': lambda name: to_camel_case (name, java=False),
	'java': lambda name: to_camel_case (name, java=True),
}

def convert_case (name, style):
	'''
	Converts name to the given style. Style may be one of:
		- 'lower': 'foo_barBaz' -> 'foo_bar_baz'
		- 'upper': 'foo_barBaz' -> 'FOO_BAR_BAZ'
		- 'camel': 'foo_barBaz' -> 'FooBarBaz'
		- 'java': 'foo_barBaz' -> 'fooBarBaz'
	'''
	try:
		stylefunc = case_styles[style]
	except KeyError:
		validstyles = ', '.join (sorted (case_styles.keys()))
		raise ValueError ('Unknown style "%s", should be one of: %s' % (style, validstyles))
	else:
		return stylefunc (name)

mercurial