Viewing file: NumberFormatter.py (3.29 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
import re from Ft.Xml.Xslt import XsltException, Error
# Pattern for format tokens (see spec 7.7.1) _token_re = re.compile('(\W*)(\w+)(\W*)', re.UNICODE)
class Formatter:
def __init__(self, format): self._format = format groups = _token_re.findall(format) if not groups: raise XsltException(Error.ILLEGAL_NUMBER_FORMAT_VALUE, self._format)
self.prefix = groups[0][0] self.suffix = groups[-1][2] toks = self.tokens = [] seps = self.separators = [] for group in groups[:-1]: toks.append(group[1]) seps.append(group[2]) toks.append(groups[-1][1]) if not seps: seps.append('.') return
def format(self, numbers, groupSize, groupSeparator): raise NotImplementedError
class DefaultFormatter(Formatter):
def format(self, numbers, groupSize, groupSeparator): result = [] zipped = map(None, numbers, self.tokens, self.separators) last_separator = self.prefix for number, token, separator in zipped[:len(numbers)]: if number < 0: number = 0 result.append(last_separator) token = token or self.tokens[-1] last_separator = separator or self.separators[-1] if token[-1] == '1': result.append(self._numeric(number, len(token), groupSize, groupSeparator)) elif re.match('[A-HJ-Za-hj-z]$', token): result.append(self._alpha(number, token[0])) elif token in ('I', 'i'): result.append(self._roman(number, token.islower())) else: raise XsltException(Error.ILLEGAL_NUMBER_FORMAT_VALUE, self._format)
result.append(self.suffix) return u''.join(result)
def _numeric(self, number, digits, groupSize, groupSeparator): numeric = '%0*d' % (digits, number) if not groupSize: return numeric
result = [] start_seg = 0 end_seg = len(numeric) % groupSize while end_seg <= len(numeric): if end_seg: result.append(numeric[start_seg:end_seg]) start_seg = end_seg end_seg += size return groupSeparator.join(result)
def _alpha(self, number, baseLetter): base = ord(baseLetter) result = [] while number: number, remainder = divmod(number - 1, 26) result.insert(0, chr(base + remainder)) return ''.join(result) _roman_1000 = ('', 'M', 'MM', 'MMM', 'MMMM') _roman_100 = ('', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM') _roman_10 = ('', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC') _roman_1 = ('', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX')
def _roman(self, number, lowercase): if number >= 5000: raise ValueError('unable to convert %d to roman numerals' % number)
roman = self._roman_1000[number / 1000] + \ self._roman_100[(number / 100) % 10] + \ self._roman_10[(number / 10) % 10] + \ self._roman_1[number % 10]
if lowercase: return roman.lower() return roman
|