tools/caseconversions.py

changeset 272
9d52b119b3f5
parent 271
416e8c497829
child 273
57952c5ca59b
equal deleted inserted replaced
271:416e8c497829 272:9d52b119b3f5
1 #!/usr/bin/env python
2 # coding: utf-8
3
4 '''
5 Provides facilities to converting identifier cases.
6 '''
7
8 #
9 # Copyright 2015 Teemu Piippo
10 # All rights reserved.
11 #
12 # Redistribution and use in source and binary forms, with or without
13 # modification, are permitted provided that the following conditions
14 # are met:
15 #
16 # 1. Redistributions of source code must retain the above copyright
17 # notice, this list of conditions and the following disclaimer.
18 # 2. Redistributions in binary form must reproduce the above copyright
19 # notice, this list of conditions and the following disclaimer in the
20 # documentation and/or other materials provided with the distribution.
21 # 3. Neither the name of the copyright holder nor the names of its
22 # contributors may be used to endorse or promote products derived from
23 # this software without specific prior written permission.
24 #
25 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
28 # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
29 # OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 #
37
38 import string
39 import re
40
41 def to_one_case (name, tolower):
42 '''
43 Convers name to either all uppercase or all lowercase (depending on the truth value of tolower), using underscores
44 as delimiters.
45 '''
46 result = ""
47 targetSet = (string.ascii_lowercase if tolower else string.ascii_uppercase) + string.digits
48 inverseSet = (string.ascii_uppercase if tolower else string.ascii_lowercase)
49 isUnderscorable = lambda ch: ch in string.ascii_uppercase \
50 or ch in string.whitespace or ch in string.punctuation
51 previousWasUnderscorable = isUnderscorable (name[0])
52
53 for ch in name:
54 if isUnderscorable (ch) and result != "" and not previousWasUnderscorable:
55 result += "_"
56
57 if ch in inverseSet:
58 result += (ch.lower() if tolower else ch.upper())
59 elif ch in targetSet:
60 result += ch
61 previousWasUnderscorable = isUnderscorable (ch)
62
63 return result
64
65 def to_camel_case (name, java = False):
66 '''
67 Converts name to camelcase. If java is False, the first letter will be lowercase, otherwise it will be uppercase.
68 '''
69 result = ""
70 wantUpperCase = False
71
72 # If it's all uppercase, make it all lowercase so that this algorithm can digest it
73 if name == name.upper():
74 name = name.lower()
75
76 for ch in name:
77 if ch == '_':
78 wantUpperCase = True
79 continue
80
81 if wantUpperCase:
82 if ch in string.ascii_lowercase:
83 ch = ch.upper()
84 wantUpperCase = False
85
86 result += ch
87
88 if java:
89 match = re.match (r'^([A-Z]+)([A-Z].+)$', result)
90 if match:
91 result = match.group (1).lower() + match.group (2)
92 else:
93 result = result[0].lower() + result[1:]
94 else:
95 result = result[0].upper() + result[1:]
96 return result
97
98 case_styles = {
99 'lower': lambda name: to_one_case (name, tolower=True),
100 'upper': lambda name: to_one_case (name, tolower=False),
101 'camel': lambda name: to_camel_case (name, java=False),
102 'java': lambda name: to_camel_case (name, java=True),
103 }
104
105 def convert_case (name, style):
106 '''
107 Converts name to the given style. Style may be one of:
108 - 'lower': 'foo_barBaz' -> 'foo_bar_baz'
109 - 'upper': 'foo_barBaz' -> 'FOO_BAR_BAZ'
110 - 'camel': 'foo_barBaz' -> 'FooBarBaz'
111 - 'java': 'foo_barBaz' -> 'fooBarBaz'
112 '''
113 try:
114 stylefunc = case_styles[style]
115 except KeyError:
116 validstyles = ', '.join (sorted (case_styles.keys()))
117 raise ValueError ('Unknown style "%s", should be one of: %s' % (style, validstyles))
118 else:
119 return stylefunc (name)

mercurial