about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/docutils/utils/roman.py
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/docutils/utils/roman.py
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are here HEAD master
Diffstat (limited to '.venv/lib/python3.12/site-packages/docutils/utils/roman.py')
-rw-r--r--.venv/lib/python3.12/site-packages/docutils/utils/roman.py154
1 files changed, 154 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/docutils/utils/roman.py b/.venv/lib/python3.12/site-packages/docutils/utils/roman.py
new file mode 100644
index 00000000..df0c5b33
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/docutils/utils/roman.py
@@ -0,0 +1,154 @@
+##############################################################################
+#
+# Copyright (c) 2001 Mark Pilgrim and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Convert to and from Roman numerals"""
+
+__author__ = "Mark Pilgrim (f8dy@diveintopython.org)"
+__version__ = "1.4"
+__date__ = "8 August 2001"
+__copyright__ = """Copyright (c) 2001 Mark Pilgrim
+
+This program is part of "Dive Into Python", a free Python tutorial for
+experienced programmers.  Visit http://diveintopython.org/ for the
+latest version.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the Python 2.1.1 license, available at
+http://www.python.org/2.1.1/license.html
+"""
+
+import argparse
+import re
+import sys
+
+
+# Define exceptions
+class RomanError(Exception):
+    pass
+
+
+class OutOfRangeError(RomanError):
+    pass
+
+
+class NotIntegerError(RomanError):
+    pass
+
+
+class InvalidRomanNumeralError(RomanError):
+    pass
+
+
+# Define digit mapping
+romanNumeralMap = (('M', 1000),
+                   ('CM', 900),
+                   ('D', 500),
+                   ('CD', 400),
+                   ('C', 100),
+                   ('XC', 90),
+                   ('L', 50),
+                   ('XL', 40),
+                   ('X', 10),
+                   ('IX', 9),
+                   ('V', 5),
+                   ('IV', 4),
+                   ('I', 1))
+
+
+def toRoman(n):
+    """convert integer to Roman numeral"""
+    if not isinstance(n, int):
+        raise NotIntegerError("decimals can not be converted")
+    if not (-1 < n < 5000):
+        raise OutOfRangeError("number out of range (must be 0..4999)")
+
+    # special case
+    if n == 0:
+        return 'N'
+
+    result = ""
+    for numeral, integer in romanNumeralMap:
+        while n >= integer:
+            result += numeral
+            n -= integer
+    return result
+
+
+# Define pattern to detect valid Roman numerals
+romanNumeralPattern = re.compile("""
+    ^                   # beginning of string
+    M{0,4}              # thousands - 0 to 4 M's
+    (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
+                        #            or 500-800 (D, followed by 0 to 3 C's)
+    (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
+                        #        or 50-80 (L, followed by 0 to 3 X's)
+    (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
+                        #        or 5-8 (V, followed by 0 to 3 I's)
+    $                   # end of string
+    """, re.VERBOSE)
+
+
+def fromRoman(s):
+    """convert Roman numeral to integer"""
+    if not s:
+        raise InvalidRomanNumeralError('Input can not be blank')
+
+    # special case
+    if s == 'N':
+        return 0
+
+    if not romanNumeralPattern.search(s):
+        raise InvalidRomanNumeralError('Invalid Roman numeral: %s' % s)
+
+    result = 0
+    index = 0
+    for numeral, integer in romanNumeralMap:
+        while s[index:index + len(numeral)] == numeral:
+            result += integer
+            index += len(numeral)
+    return result
+
+
+def parse_args():
+    parser = argparse.ArgumentParser(
+        prog='roman',
+        description='convert between roman and arabic numerals'
+    )
+    parser.add_argument('number', help='the value to convert')
+    parser.add_argument(
+        '-r', '--reverse',
+        action='store_true',
+        default=False,
+        help='convert roman to numeral (case insensitive) [default: False]')
+
+    args = parser.parse_args()
+    args.number = args.number
+    return args
+
+
+def main():
+    args = parse_args()
+    if args.reverse:
+        u = args.number.upper()
+        r = fromRoman(u)
+        print(r)
+    else:
+        i = int(args.number)
+        n = toRoman(i)
+        print(n)
+
+    return 0
+
+
+if __name__ == "__main__":  # pragma: no cover
+    sys.exit(main())  # pragma: no cover