├── .gitignore ├── .travis.yml ├── README.md ├── ScreenShot.JPG ├── Source ├── 22B725F3-E203-4DAE-B0A1-3030FE350A2D.png ├── NumToCny.py ├── NumToEng.py ├── icon.png ├── info.plist ├── source.py └── test.py └── 人民币金额大写.alfredworkflow /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # PyInstaller 26 | # Usually these files are written by a python script from a template 27 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 28 | *.manifest 29 | *.spec 30 | 31 | # Installer logs 32 | pip-log.txt 33 | pip-delete-this-directory.txt 34 | 35 | # Unit test / coverage reports 36 | htmlcov/ 37 | .tox/ 38 | .coverage 39 | .cache 40 | nosetests.xml 41 | coverage.xml 42 | 43 | # Translations 44 | *.mo 45 | *.pot 46 | 47 | # Django stuff: 48 | *.log 49 | 50 | # Sphinx documentation 51 | docs/_build/ 52 | 53 | # PyBuilder 54 | target/ 55 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | script: python ./Source/test.py 4 | 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Alfred_NumToCny 2 | 3 | [![Build Status](https://travis-ci.org/yourtion/Alfred_NumToCny.svg?branch=master)](https://travis-ci.org/yourtion/Alfred_NumToCny) 4 | 5 | ## 转换数字为人民币金额的 Alfred Workflow 6 | 7 | ![](ScreenShot.JPG) 8 | -------------------------------------------------------------------------------- /ScreenShot.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yourtion/Alfred_NumToCny/e660a095985f43d75c3c1045c7bce97f526cb180/ScreenShot.JPG -------------------------------------------------------------------------------- /Source/22B725F3-E203-4DAE-B0A1-3030FE350A2D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yourtion/Alfred_NumToCny/e660a095985f43d75c3c1045c7bce97f526cb180/Source/22B725F3-E203-4DAE-B0A1-3030FE350A2D.png -------------------------------------------------------------------------------- /Source/NumToCny.py: -------------------------------------------------------------------------------- 1 | #encoding: utf-8 2 | ''' 3 | 中文互联网上迄今为止实现最正确、代码最漂亮且效率最高的大写人民币金额转换代码 4 | 作者:李维 5 | 版权所有 (c) 2013 李维。保留所有权利。 6 | 本代码基于 BSD License 授权。 7 | ''' 8 | 9 | from cStringIO import StringIO 10 | from decimal import Decimal 11 | import math 12 | 13 | _RMB_DIGITS = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖' ] 14 | _SECTION_CHARS = ['', '拾', '佰', '仟', '万' ] 15 | 16 | def to_rmb_upper(price): 17 | price = Decimal(price) 18 | price = Decimal('{:.2f}'.format(price)) 19 | integer_part = int(price) 20 | wanyi_part = integer_part / 1000000000000 21 | yi_part = integer_part % 1000000000000 / 100000000 22 | wan_part = integer_part % 100000000 / 10000 23 | qian_part = integer_part % 10000 24 | dec_part = int(price * 100 % 100) 25 | 26 | 27 | strio = StringIO() 28 | 29 | zero_count = 0 30 | #处理万亿以上的部分 31 | if integer_part >= 1000000000000 and wanyi_part > 0: 32 | zero_count = _parse_integer(strio, wanyi_part, zero_count, True) 33 | if yi_part > 0: 34 | strio.write('万') 35 | else: 36 | strio.write('万亿') 37 | 38 | #处理亿到千亿的部分 39 | if integer_part >= 100000000 and yi_part > 0: 40 | is_first_section = integer_part >= 100000000 and integer_part < 1000000000000 41 | zero_count = _parse_integer(strio, yi_part, zero_count, is_first_section) 42 | strio.write('亿') 43 | 44 | #处理万的部分 45 | if integer_part >= 10000 and wan_part > 0: 46 | is_first_section = integer_part >= 1000 and integer_part < 10000000 47 | zero_count = _parse_integer(strio, wan_part, zero_count, is_first_section) 48 | strio.write('万') 49 | 50 | #处理千及以后的部分 51 | if qian_part > 0: 52 | is_first_section = integer_part < 1000 53 | zero_count = _parse_integer(strio, qian_part, zero_count, is_first_section) 54 | else: 55 | zero_count += 1 56 | if integer_part > 0: 57 | strio.write('圆') 58 | 59 | #处理小数 60 | if dec_part > 0: 61 | _parse_decimal(strio, integer_part, dec_part, zero_count) 62 | elif dec_part == 0 and integer_part > 0: 63 | strio.write('整') 64 | else: 65 | strio.write('零圆整') 66 | 67 | return strio.getvalue() 68 | 69 | def _parse_integer(strio, value, zero_count = 0, is_first_section = False): 70 | assert value > 0 and value <= 9999 71 | ndigits = int(math.floor(math.log10(value))) + 1 72 | if value < 1000 and not is_first_section: 73 | zero_count += 1 74 | for i in xrange(0, ndigits): 75 | factor = int(pow(10, ndigits - 1 - i)) 76 | digit = int(value / factor) 77 | if digit != 0: 78 | if zero_count > 0: 79 | strio.write('零') 80 | strio.write(_RMB_DIGITS[digit]) 81 | strio.write(_SECTION_CHARS[ndigits - i - 1]) 82 | zero_count = 0 83 | else: 84 | zero_count += 1 85 | value -= value / factor * factor 86 | return zero_count 87 | 88 | def _parse_decimal(strio, integer_part, value, zero_count): 89 | assert value > 0 and value <= 99 90 | jiao = value / 10 91 | fen = value % 10 92 | if zero_count > 0 and (jiao > 0 or fen > 0) and integer_part > 0: 93 | strio.write('零') 94 | if jiao > 0: 95 | strio.write(_RMB_DIGITS[jiao]) 96 | strio.write('角') 97 | if zero_count == 0 and jiao == 0 and fen > 0 and integer_part > 0: 98 | strio.write('零') 99 | if fen > 0: 100 | strio.write(_RMB_DIGITS[fen]) 101 | strio.write('分') 102 | else: 103 | strio.write('整') 104 | -------------------------------------------------------------------------------- /Source/NumToEng.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | _SUFFIXES = ["", "thousand", "million", "billion"]; 5 | _ONES = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"]; 6 | _AFTER_TEN = ["ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"]; 7 | _TENS = ["twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety", "hundred"]; 8 | 9 | #handles the nomenclature of a triplet 10 | #number: the number in the string form, index: position of the triplet 11 | def gimmeThemWords(number, index): 12 | length = len(number); 13 | 14 | if(length > 3): 15 | return False; 16 | 17 | #pads the number's string representation with 0s on the left 18 | number = number.zfill(3); 19 | string = ""; 20 | 21 | hundreds_digit = ord(number[0]) - 48; 22 | tens_digit = ord(number[1]) - 48; 23 | ones_digit = ord(number[2]) - 48; 24 | 25 | string += "" if number[0] == '0' else _ONES[hundreds_digit]; 26 | string += " hundred " if not string == "" else ""; 27 | 28 | if(tens_digit > 1): 29 | string += _TENS[tens_digit - 2]; 30 | string += " "; 31 | string += _ONES[ones_digit]; 32 | 33 | elif(tens_digit == 1): 34 | string += _AFTER_TEN[(int(tens_digit + ones_digit) % 10) - 1]; 35 | 36 | elif(tens_digit == 0): 37 | string += _ONES[ones_digit]; 38 | 39 | #counter check to determine the positional system 40 | if(string.endswith("zero")): 41 | string = string[:-len("zero")]; 42 | 43 | else: 44 | string += " "; 45 | 46 | if(not len(string) == 0): 47 | string += _SUFFIXES[index]; 48 | 49 | return string; 50 | 51 | def not_empty(s): 52 | return not len(s.strip()) == 0 53 | 54 | #initiates the process of converting the number into its cardinal form 55 | def to_eng(number): 56 | length = len(str(number)); 57 | 58 | #counter contains the number of size- 3 groupings of digits that can be formed from the number 59 | counter = int(length / 3) if length % 3 == 0 else int(length / 3) + 1; 60 | counter_copy = counter; 61 | word_representation = []; 62 | 63 | for i in range(length - 1, -1, -3): 64 | word_representation.append(gimmeThemWords(str(number)[0 if i - 2 < 0 else i - 2 : i + 1], counter_copy - counter)); 65 | counter -= 1; 66 | res = ", ".join(filter(not_empty, reversed(word_representation))).strip() 67 | return res.capitalize() 68 | -------------------------------------------------------------------------------- /Source/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yourtion/Alfred_NumToCny/e660a095985f43d75c3c1045c7bce97f526cb180/Source/icon.png -------------------------------------------------------------------------------- /Source/info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | bundleid 6 | Yourtion.tools.cny 7 | category 8 | Tools 9 | connections 10 | 11 | 22B725F3-E203-4DAE-B0A1-3030FE350A2D 12 | 13 | 14 | destinationuid 15 | E0FEAA98-6136-4769-B2FE-DF95334AAF44 16 | modifiers 17 | 0 18 | modifiersubtext 19 | 20 | vitoclose 21 | 22 | 23 | 24 | 25 | createdby 26 | Yourtion Guo 27 | description 28 | 转换数字为人民币金额 29 | disabled 30 | 31 | name 32 | 人民币金额大写 33 | objects 34 | 35 | 36 | config 37 | 38 | alfredfiltersresults 39 | 40 | argumenttype 41 | 0 42 | escaping 43 | 1 44 | keyword 45 | cny 46 | queuedelaycustom 47 | 3 48 | queuedelayimmediatelyinitially 49 | 50 | queuedelaymode 51 | 0 52 | queuemode 53 | 1 54 | runningsubtext 55 | 56 | script 57 | #encoding: utf-8 58 | 59 | import NumToCny 60 | import json 61 | 62 | def parse(strs): 63 | res = { "title": strs, "subtitle": "Copy to clipboard","arg": strs, "icon": "icon.png" } 64 | return { "items": [res] } 65 | 66 | ret = NumToCny.to_rmb_upper('{query}') 67 | 68 | print(json.dumps(parse(ret))) 69 | scriptargtype 70 | 0 71 | scriptfile 72 | 73 | subtext 74 | 输入人民币数字金额 75 | title 76 | 人民币 {query} 77 | type 78 | 3 79 | withspace 80 | 81 | 82 | type 83 | alfred.workflow.input.scriptfilter 84 | uid 85 | 22B725F3-E203-4DAE-B0A1-3030FE350A2D 86 | version 87 | 2 88 | 89 | 90 | config 91 | 92 | autopaste 93 | 94 | clipboardtext 95 | {query} 96 | transient 97 | 98 | 99 | type 100 | alfred.workflow.output.clipboard 101 | uid 102 | E0FEAA98-6136-4769-B2FE-DF95334AAF44 103 | version 104 | 2 105 | 106 | 107 | readme 108 | 转换数字为人民币金额 109 | uidata 110 | 111 | 22B725F3-E203-4DAE-B0A1-3030FE350A2D 112 | 113 | xpos 114 | 300 115 | ypos 116 | 120 117 | 118 | E0FEAA98-6136-4769-B2FE-DF95334AAF44 119 | 120 | xpos 121 | 700 122 | ypos 123 | 120 124 | 125 | 126 | version 127 | 1.5 128 | webaddress 129 | https://github.com/yourtion/Alfred_NumToCny 130 | 131 | 132 | -------------------------------------------------------------------------------- /Source/source.py: -------------------------------------------------------------------------------- 1 | #encoding: utf-8 2 | 3 | import NumToCny 4 | import NumToEng 5 | import json 6 | 7 | def parse(strs, strs2): 8 | res = { "title": strs, "subtitle": "Copy to clipboard","arg": strs, "icon": "icon.png" } 9 | res2 = { "title": strs2, "subtitle": "Copy to clipboard","arg": strs2, "icon": "icon.png" } 10 | return { "items": [res, res2] } 11 | 12 | ret = NumToCny.to_rmb_upper('{query}') 13 | ret2 = NumToEng.to_eng('{query}') 14 | 15 | print(json.dumps(parse(ret, ret2))) 16 | -------------------------------------------------------------------------------- /Source/test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import NumToCny 5 | import unittest 6 | 7 | CASE1 = [ 8 | ['1', '壹圆整'], 9 | ['20', '贰拾圆整'], 10 | ['100', '壹佰圆整'], 11 | ['1000', '壹仟圆整'], 12 | ['30000', '叁万圆整'], 13 | ['400000', '肆拾万圆整'], 14 | ['5000000', '伍佰万圆整'], 15 | ['60000000', '陆仟万圆整'], 16 | ['700000000', '柒亿圆整'], 17 | ['8000000000', '捌拾亿圆整'], 18 | ['90000000000', '玖佰亿圆整'], 19 | ['100000000000', '壹仟亿圆整'], 20 | ['2000000000000', '贰万亿圆整'], 21 | ['30000000000000', '叁拾万亿圆整'], 22 | ['400000000000000', '肆佰万亿圆整'], 23 | ['5000000000000000', '伍仟万亿圆整'] 24 | ] 25 | 26 | CASE2 = [ 27 | ['1000000001234', '壹万亿壹仟贰佰叁拾肆圆整'], 28 | ['1212.1', '壹仟贰佰壹拾贰圆壹角整'], 29 | ] 30 | 31 | class NumToCnyTestCase(unittest.TestCase): 32 | def testInt(self): 33 | for case in CASE1: 34 | res = NumToCny.to_rmb_upper(case[0]) 35 | self.assertEqual(res, case[1]) 36 | for case in CASE2: 37 | res = NumToCny.to_rmb_upper(case[0]) 38 | self.assertEqual(res, case[1]) 39 | 40 | if __name__ == '__main__': 41 | unittest.main() 42 | -------------------------------------------------------------------------------- /人民币金额大写.alfredworkflow: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yourtion/Alfred_NumToCny/e660a095985f43d75c3c1045c7bce97f526cb180/人民币金额大写.alfredworkflow --------------------------------------------------------------------------------