Skip to content

Commit

Permalink
Release 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
ENDrain committed Apr 16, 2021
2 parents bd3ebf5 + 19a6111 commit e8daf32
Show file tree
Hide file tree
Showing 8 changed files with 253 additions and 48 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ share/python-wheels/
.installed.cfg
*.egg
MANIFEST
pyproject.toml

# PyInstaller
# Usually these files are written by a python script from a template
Expand Down
42 changes: 42 additions & 0 deletions INTRODUCTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# ABOUT CHURCH SLAVONIC NUMBERS

## 1. Numerals

Church Slavonic script (*further CU*) has individual numerals to represent numbers from 1 to 9, each round ten and each round hundred, for a total of 27 numerals. There's no zero digit.

## 2. Basic numbers

A number `x < 1000` in CU is represented by a succession of 1 to 3 CU digits that may contain a hundreds digit, a tens digit and a proper digit in that order. Digits representing numbers 11-19 are swapped places, wheter or not a hundreds digit is present.

For the purpose of this program, this is to be referenced as a "hundred group".

**Examples:**
CU | Arabic
---|---
а҃ | 1
і҃ | 10
р҃ | 100
ра҃і | 111 - note digit swapping
рк҃а | 121

## 3. Thousands
A number `x >= 1000` in CU is prepended with a "thousand" sign. For each "thousand" sign before a number, the number has to be mutiplied by one thousand.

## 4. Number building

Altogether, a complete number in CU consists of a succession of hundred groups with "thousand" signs inbetween.

**Examples:**
CU | Arabic
---|---
а҃ | 1
҂а҃ | 1000
҂҂а҃ | 1000000
҂҂а҂аа҃ | 1001001

## 5. Decoration
Finally, there is a "titlo" superscript sign that's obligatory to CU numbers. "Titlo" is placed in the number's rightmost hundred group; above the 2nd-from-last digit if it exists, otherwise above the only digit.

**Examples:**

See examples above. **NB:** in some (many) fonts "titlo" appears to follow after a digit, not above it.
42 changes: 41 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,41 @@
A program for number convertion between Church Slavonic and arabic.
# cu-numbers

A program for numbers conversion between Church Slavonic script (*further CU*) and Arabic numerals.

## Background

See [Introduction](./INTRODUCTION.md) to learn about CU numbers.

## Requirements

Python >= 3.7

## Installation

pip install cu-numbers

## Usage

import cunumbers

# Convert an Arabic number to CU
# Requires non-zero int, returns str

a = cunumbers.arab_to_cu(1)

# Convert a CU number to an Arabic
# Requires str, returns int

b = cunumbers.cu_to_arab("а҃")

## Contributing

Create an issue describing a bug or suggestion, then create a pull request mentioning the issue.

## Feedback

Drop me a line: [email protected]

## License

See [LICENSE](./LICENSE).
1 change: 1 addition & 0 deletions cunumbers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .cunumbers import arab_to_cu, cu_to_arab
106 changes: 59 additions & 47 deletions cu-numbers.py → cunumbers/cunumbers.py
Original file line number Diff line number Diff line change
@@ -1,38 +1,7 @@
# ABOUT CHURCH SLAVONIC NUMBERS
#
# Church Slavonic (CS) script has individual digits to represent numbers from 1 to 9,
# each round ten and each round hundred, for a total of 27 digits. There's no zero digit.
#
# A number x < 1000 in CS script is represented by a succession of 1 to 3 CS digits
# that may contain a hundreds digit, a tens digit and a proper digit in that order.
# Digits representing numbers 11-19 are swapped places, wheter or not a hundreds digit is present.
#
# For the purpose of this program, this is to be referenced as "a hundred group".
#
# Examples:
# а҃ = 1
# і҃ = 10
# р҃ = 100
# ра҃і = 111 - note the digit swapping
# рк҃а = 121
#
# A number x >= 1000 in CS script is prepended with a "thousand" sign.
# For each "thousand" sign before a number, the number has to be mutiplied by a thousand.
#
# Altogether, a complete number in CS script consists of a succession of hundred groups
# with "thousand" signs inbetween.
#
# Examples:
# а҃ = 1
# ҂а҃ = 1000
# ҂҂а҃ = 1000000
# ҂҂а҂аа҃ = 1001001
#
# There's also a "titlo" superscript sign that's obligatory to Church Slavonic numbers.
# "Titlo" is placed in the number's rightmost hundred group;
# above the 2nd-from-last digit if it exists, otherwise above the only digit.
# See examples above.

# For licensing information see LICENSE file included in the project's root directory.
"""
Module for number conversion between Church Slavonic and Arabic.
"""

import re

Expand All @@ -46,22 +15,22 @@
cu_dict = cu_null + cu_digits + cu_null + cu_tens + cu_null + cu_hundreds


# Process an arabic hundred group
def _write_cu_hundred(hundred):
def _write_cu_hundred(hundred = 0):
"""Process an arabic hundred group."""
return cu_dict[20 + hundred // 100] + cu_dict[10 + hundred % 100 // 10] + cu_dict[hundred % 10]


# Process an arabic number in hundred groups
def _write_cu_number(index, number, result):
def _write_cu_number(number = 0, index = 0, result = ""):
"""Process an arabic number per hundred group."""
# @index arg counts the amount of hundred groups in a number
# to add the appropriate amount of the "҂" between each hundred group.
# to add the appropriate amount of "҂" before each hundred group.

# Process leading hundred. Prepend with "҂" times @index if @index > 0
sub_result = cu_thousand * index + _write_cu_hundred(number % 1000) + result

if number // 1000:
# If the number is still >1000: @index++, drop last 3 digits and repeat
return _write_cu_number(index + 1, number // 1000, sub_result)
return _write_cu_number(number // 1000, index + 1, sub_result)

else:
# Purge zero-groups and individual zeroes
Expand All @@ -77,7 +46,8 @@ def _write_cu_number(index, number, result):
return sub_result # And we're done


def _read_cu_hundred(index, input):
def _read_cu_hundred(input = "" , index = 0):
"""Process a CU hundred group."""
# @index arg holds current position of a hundred group in the number

# Swap digits in numbers 11-19
Expand All @@ -102,9 +72,10 @@ def _read_cu_hundred(index, input):
return subtotal


# Process a Church Slavonic number
def _read_cu_number(input):
sub_result = str.strip(input)
def _read_cu_number(input = ""):
"""Process a CU number per hundred group."""

sub_result = input

# Strip ҃"҃ "
sub_result = re.sub("[%s]" % cu_titlo, "", input)
Expand All @@ -118,6 +89,47 @@ def _read_cu_number(input):

result = 0
for i, k in enumerate(hundreds):
result += _read_cu_hundred(i, k[::-1])
result += _read_cu_hundred(k[::-1], i)

return(result)


def prepare(input):
"""Prepare a CU number for conversion."""

input = str.lower(str.strip(input)) # Trim and lowercase
if re.fullmatch("([%s]*[%s]{1,4})+" % (cu_thousand, cu_digits + cu_tens + cu_hundreds + cu_titlo), input) == None:
raise ValueError("String does not match the pattern for Church Slavonic script number")
else:
return input


return(result)

def arab_to_cu(input):
"""
Convert an Arabic number into Church Slavonic script.
Requires a non-zero integer.
"""

t = type(input)
if t != int:
raise TypeError("Non-zero integer required, got %s" % t)
elif input <= 0:
raise ValueError("Non-zero integer required")
else:
return _write_cu_number(input)


def cu_to_arab(input: str):
"""
Convert a Church Slavonic script number into Arabic.
Requires a string.
"""

t = type(input)
if t != str:
raise TypeError("String required, got %s" % t)
else:
return _read_cu_number(prepare(input))
25 changes: 25 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[metadata]
name = cu-numbers
version = 1.0.0
author = Andrei Shur
author_email = [email protected]
description = Church Slavonic script numbers conversion
long_description = file: README.md
long_description_content_type = text/markdown
url = https://github.com/endrain/cu-numbers
keywords = church slavonic, conversion
license = MIT
classifiers =
Development Status :: 5 - Production/Stable
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
License :: OSI Approved :: MIT License
Operating System :: OS Independent
Intended Audience :: Religion
Intended Audience :: Science/Research

[options]
include_package_data = True
packages = cunumbers
python_requires = >=3.7
Empty file added tests/__init__.py
Empty file.
84 changes: 84 additions & 0 deletions tests/test_cunumbers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import unittest, cunumbers
arab_to_cu = cunumbers.arab_to_cu
cu_to_arab = cunumbers.cu_to_arab

class arab_to_cuTestCase(unittest.TestCase):
def test_arab_to_cu_digits(self):
self.assertEqual(arab_to_cu(1), "а҃")
self.assertEqual(arab_to_cu(9), "ѳ҃")

def test_arab_to_cu_tens(self):
self.assertEqual(arab_to_cu(10), "і҃")
self.assertEqual(arab_to_cu(18), "и҃і")
self.assertEqual(arab_to_cu(22), "к҃в")

def test_arab_to_cu_hundreds(self):
self.assertEqual(arab_to_cu(100), "р҃")
self.assertEqual(arab_to_cu(207), "с҃з")
self.assertEqual(arab_to_cu(333), "тл҃г")

def test_arab_to_cu_thousand(self):
self.assertEqual(arab_to_cu(1000), "҂а҃")
self.assertEqual(arab_to_cu(1006), "҂аѕ҃")
self.assertEqual(arab_to_cu(1015), "҂ає҃і")
self.assertEqual(arab_to_cu(1444), "҂аум҃д")

def test_arab_to_cu_big(self):
self.assertEqual(arab_to_cu(10001010001), "҂҂҂і҂҂а҂іа҃")
self.assertEqual(arab_to_cu(50000000000), "҂҂҂н҃")
self.assertEqual(arab_to_cu(60000070000), "҂҂҂ѯ҂ѻ҃")

class cu_to_arabTestCase(unittest.TestCase):
def test_cu_to_arab_digits(self):
self.assertEqual(1, cu_to_arab("а҃"))
self.assertEqual(9, cu_to_arab("ѳ"))

def test_cu_to_arab_tens(self):
self.assertEqual(10, cu_to_arab("і҃"))
self.assertEqual(18, cu_to_arab("и҃і"))
self.assertEqual(22, cu_to_arab("к҃в"))

def test_cu_to_arab_hundreds(self):
self.assertEqual(100, cu_to_arab("р҃"))
self.assertEqual(207, cu_to_arab("с҃з"))
self.assertEqual(333, cu_to_arab("тл҃г"))

def test_cu_to_arab_thousands(self):
self.assertEqual(1000, cu_to_arab("҂а҃"))
self.assertEqual(1006, cu_to_arab("҂аѕ҃"))
self.assertEqual(1015, cu_to_arab("҂ає҃і"))
self.assertEqual(1444, cu_to_arab("҂аум҃д"))

def test_cu_to_arab_big(self):
self.assertEqual(10001010001, cu_to_arab("҂҂҂і҂҂а҂іа҃"))
self.assertEqual(50000000000, cu_to_arab("҂҂҂н҃"))
self.assertEqual(60000070000, cu_to_arab("҂҂҂ѯ҂ѻ҃"))

def test_cu_to_arab_no_tsnd(self):
self.assertEqual(80500690700, cu_to_arab("пфхчѱ҃"))

def test_cu_to_arab_no_titlo(self):
self.assertEqual(1, cu_to_arab("а"))

def test_cu_to_arab_spaced(self):
self.assertEqual(1, cu_to_arab("а҃ "))

def test_cu_to_arab_uppercase(self):
self.assertEqual(1, cu_to_arab("А҃"))

def test_cu_to_arab_mixed(self):
self.assertEqual(2021, cu_to_arab(" вКА"))

class ErrorTestCase(unittest.TestCase):
def test_arab_to_cu_error(self):
self.assertRaises(TypeError, arab_to_cu, "String")
self.assertRaises(TypeError, arab_to_cu, 9.75)
self.assertRaises(ValueError, arab_to_cu, 0)
self.assertRaises(ValueError, arab_to_cu, -69)

def test_cu_to_arab_error(self):
self.assertRaises(TypeError, cu_to_arab, 420)
self.assertRaises(ValueError, cu_to_arab, "A113")

if __name__ == '__main__':
unittest.main()

0 comments on commit e8daf32

Please sign in to comment.