Underscore/Camelcase insensitivity
Alexander Schmolck
a.schmolck at gmx.net
Mon Feb 24 20:09:48 EST 2003
m.faassen at vet.uu.nl (Martijn Faassen) writes:
> the camelCase convention. This week I was pondering making a mixin class which
> helps us transition underscore to camelcase automatically. So, in a way
> I was even serious here.
>
>
I've actually discovered that converting from and to camelCase is really much
more of a pain than you'd think (I might just be doing it stupidly). Anyway,
here's the horribly convoluted code I came up with some time ago, in case it
is of any use for your enterprise.
alex
import string
_UP = string.uppercase # XXX is that what we should use?
_lo = string.lowercase
_UP_0_9 = _UP + string.digits
def camelJoin(strs, capitalizeFirst=True):
"""Join `strs` to a CamelCasedWord.
"""
if len(strs) == 1:
parts = strs
else:
parts = []
for this, next in xwindow(strs):
if this[-1] in _UP:
if (next[-1] in _UP_0_9):
parts.append(this + "_")
else:
parts.append(this)
else:
parts.append(this.capitalize())
if next[-1] in _UP_0_9:
parts.append(next)
else:
parts.append(next.capitalize())
if not capitalizeFirst:
parts[0] = parts[0].lower()
return "".join(parts)
def camelSplit(name, strict=True):
"""Split a CamelCase name into its components. Retains capitalization
information where it isn't used to separate words. Retains leading and
trailing 'magic' underbars.
"""
global _UP, _lo
leading_bars , mid, trailing_bars = \
re.match(r'(_+)?(.*?)(_+)?$', name).groups()
if not mid: # very special case: name ~= /_*/
return [[name], []][not name]
elif mid.isupper():
# HACK the '_*' bit is to have consecutive '_'s fail
split = re.split('(_)_*', mid)
elif "_" not in mid and name.islower():
split = [mid]
else:
# need this for trailing and leading bars, that should be preserved
r = r''' ^[lo][lo\d]*(?=[UP]|$)
|
[UP][UP\d]*(?=_[UP\d])
|
[UP][lo][lo\d]*
|
[UP][UP\d]*(?=[UP][lo]|$)
|
_ # need to keep this to reconstruct case for 1 char parts
'''
splitRE = re.compile(replaceStrs(r, ("UP", _UP), ("lo", _lo)), re.X)
if strict:
split = splitRE.findall(mid)
else:
split = reduce(operator.add, map(splitRE.findall,
re.split('(_)_*', mid)))
def normCase(t):
previous, x = t
if (re.search(r'[A-Z]{2,}',x)): return x
else: return x.lower()
# NB: split[0] is *not* normalized
split[1:] = map(normCase, xwindow(split))
split[0] = (leading_bars or "") + split[0]
split[-1] += (trailing_bars or "")
if reduce(int.__add__, map(len,split),0) != len(name):
raise ValueError("Illegal CamelCase name supplied: %s" % name)
# kick out all '_'s, except "magic" trailing and leading ones
return filter("_".__ne__, split)
def xwindow(iter, n=2, s=1):
r"""Move an `n`-item (default 2) windows `s` steps (default 1) at a time
over `iter`.
"""
assert n >= s
last = []
for elt in iter:
last.append(elt)
if len(last) == n: yield tuple(last); last=last[s:]
More information about the Python-list
mailing list