mirror of
https://github.com/kennethreitz/dive-into-python3.git
synced 2026-06-05 23:10:17 +00:00
iterators and generators chapter
--HG-- rename : humansize.py => examples/humansize.py rename : roman1.py => examples/roman1.py rename : roman2.py => examples/roman2.py rename : roman3.py => examples/roman3.py rename : roman4.py => examples/roman4.py rename : roman5.py => examples/roman5.py rename : roman6.py => examples/roman6.py rename : roman7.py => examples/roman7.py rename : roman8.py => examples/roman8.py rename : romantest1.py => examples/romantest1.py rename : romantest2.py => examples/romantest2.py rename : romantest3.py => examples/romantest3.py rename : romantest4.py => examples/romantest4.py rename : romantest5.py => examples/romantest5.py rename : romantest6.py => examples/romantest6.py rename : romantest7.py => examples/romantest7.py rename : romantest8.py => examples/romantest8.py
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
"""Fibonacci generator"""
|
||||
|
||||
def fib(max):
|
||||
a, b = 0, 1
|
||||
while a < max:
|
||||
yield a
|
||||
a, b = b, a + b
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,39 @@
|
||||
"""Fibonacci iterator"""
|
||||
|
||||
class fib:
|
||||
def __init__(self, max):
|
||||
self.max = max
|
||||
|
||||
def __iter__(self):
|
||||
self.a, self.b = 0, 1
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
fib = self.a
|
||||
if fib > self.max:
|
||||
raise StopIteration
|
||||
self.a, self.b = self.b, self.a + self.b
|
||||
return fib
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,65 @@
|
||||
"""Convert file sizes to human-readable form.
|
||||
|
||||
Available functions:
|
||||
approximate_size(size, a_kilobyte_is_1024_bytes)
|
||||
takes a file size and returns a human-readable string
|
||||
|
||||
Examples:
|
||||
>>> approximate_size(1024)
|
||||
'1.0 KiB'
|
||||
>>> approximate_size(1000, False)
|
||||
'1.0 KB'
|
||||
|
||||
"""
|
||||
|
||||
SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
|
||||
1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}
|
||||
|
||||
def approximate_size(size, a_kilobyte_is_1024_bytes=True):
|
||||
"""Convert a file size to human-readable form.
|
||||
|
||||
Keyword arguments:
|
||||
size -- file size in bytes
|
||||
a_kilobyte_is_1024_bytes -- if True (default), use multiples of 1024
|
||||
if False, use multiples of 1000
|
||||
|
||||
Returns: string
|
||||
|
||||
"""
|
||||
if size < 0:
|
||||
raise ValueError('number must be non-negative')
|
||||
|
||||
multiple = 1024 if a_kilobyte_is_1024_bytes else 1000
|
||||
for suffix in SUFFIXES[multiple]:
|
||||
size /= multiple
|
||||
if size < multiple:
|
||||
return "{0:.1f} {1}".format(size, suffix)
|
||||
|
||||
raise ValueError('number too large')
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(approximate_size(1000000000000, False))
|
||||
print(approximate_size(1000000000000))
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,48 @@
|
||||
"""Pluralize English nouns (stage 1)
|
||||
|
||||
Command line usage:
|
||||
$ python3 plural.py noun
|
||||
nouns
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
def plural(noun):
|
||||
if re.search('[sxz]$', noun):
|
||||
return re.sub('$', 'es', noun)
|
||||
elif re.search('[^aeioudgkprt]h$', noun):
|
||||
return re.sub('$', 'es', noun)
|
||||
elif re.search('[^aeiou]y$', noun):
|
||||
return re.sub('y$', 'ies', noun)
|
||||
else:
|
||||
return noun + 's'
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
if sys.argv[1:]:
|
||||
print(plural(sys.argv[1]))
|
||||
else:
|
||||
print(__doc__)
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,73 @@
|
||||
"""Pluralize English nouns (stage 2)
|
||||
|
||||
Command line usage:
|
||||
$ python plural2.py noun
|
||||
nouns
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
def match_sxz(noun):
|
||||
return re.search('[sxz]$', noun)
|
||||
|
||||
def apply_sxz(noun):
|
||||
return re.sub('$', 'es', noun)
|
||||
|
||||
def match_h(noun):
|
||||
return re.search('[^aeioudgkprt]h$', noun)
|
||||
|
||||
def apply_h(noun):
|
||||
return re.sub('$', 'es', noun)
|
||||
|
||||
def match_y(noun):
|
||||
return re.search('[^aeiou]y$', noun)
|
||||
|
||||
def apply_y(noun):
|
||||
return re.sub('y$', 'ies', noun)
|
||||
|
||||
def match_default(noun):
|
||||
return True
|
||||
|
||||
def apply_default(noun):
|
||||
return noun + 's'
|
||||
|
||||
rules = ((match_sxz, apply_sxz),
|
||||
(match_h, apply_h),
|
||||
(match_y, apply_y),
|
||||
(match_default, apply_default)
|
||||
)
|
||||
|
||||
def plural(noun):
|
||||
for matches_rule, apply_rule in rules:
|
||||
if matches_rule(noun):
|
||||
return apply_rule(noun)
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
if sys.argv[1:]:
|
||||
print(plural(sys.argv[1]))
|
||||
else:
|
||||
print(__doc__)
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,60 @@
|
||||
"""Pluralize English nouns (stage 3)
|
||||
|
||||
Command line usage:
|
||||
$ python plural3.py noun
|
||||
nouns
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
def build_match_and_apply_functions(pattern, search, replace):
|
||||
def matches_rule(word):
|
||||
return re.search(pattern, word)
|
||||
def apply_rule(word):
|
||||
return re.sub(search, replace, word)
|
||||
return (matches_rule, apply_rule)
|
||||
|
||||
patterns = \
|
||||
[
|
||||
['[sxz]$', '$', 'es'],
|
||||
['[^aeioudgkprt]h$', '$', 'es'],
|
||||
['(qu|[^aeiou])y$', 'y$', 'ies'],
|
||||
['$', '$', 's']
|
||||
]
|
||||
rules = [build_match_and_apply_functions(pattern, search, replace)
|
||||
for (pattern, search, replace) in patterns]
|
||||
|
||||
def plural(noun):
|
||||
for matches_rule, apply_rule in rules:
|
||||
if matches_rule(noun):
|
||||
return apply_rule(noun)
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
if sys.argv[1:]:
|
||||
print(plural(sys.argv[1]))
|
||||
else:
|
||||
print(__doc__)
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,4 @@
|
||||
[sxz]$ $ es
|
||||
[^aeioudgkprt]h$ $ es
|
||||
[^aeiou]y$ y$ ies
|
||||
$ $ s
|
||||
@@ -0,0 +1,60 @@
|
||||
"""Pluralize English nouns (stage 4)
|
||||
|
||||
Command line usage:
|
||||
$ python plural4.py noun
|
||||
nouns
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
def build_match_and_apply_functions(pattern, search, replace):
|
||||
def matches_rule(word):
|
||||
return re.search(pattern, word)
|
||||
def apply_rule(word):
|
||||
return re.sub(search, replace, word)
|
||||
return (matches_rule, apply_rule)
|
||||
|
||||
rules = []
|
||||
pattern_file = open('plural4-rules.txt')
|
||||
try:
|
||||
for line in pattern_file:
|
||||
pattern, search, replace = line.split(None, 3)
|
||||
rules.append(build_match_and_apply_functions(
|
||||
pattern, search, replace))
|
||||
finally:
|
||||
pattern_file.close()
|
||||
|
||||
def plural(noun):
|
||||
for matches_rule, apply_rule in rules:
|
||||
if matches_rule(noun):
|
||||
return apply_rule(noun)
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
if sys.argv[1:]:
|
||||
print(plural(sys.argv[1]))
|
||||
else:
|
||||
print(__doc__)
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,4 @@
|
||||
[sxz]$ $ es
|
||||
[^aeioudgkprt]h$ $ es
|
||||
[^aeiou]y$ y$ ies
|
||||
$ $ s
|
||||
@@ -0,0 +1,55 @@
|
||||
"""Pluralize English nouns (stage 5)
|
||||
|
||||
Command line usage:
|
||||
$ python plural5.py noun
|
||||
nouns
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
def build_match_and_apply_functions(pattern, search, replace):
|
||||
def matches_rule(word):
|
||||
return re.search(pattern, word)
|
||||
def apply_rule(word):
|
||||
return re.sub(search, replace, word)
|
||||
return (matches_rule, apply_rule)
|
||||
|
||||
def rules():
|
||||
for line in open('plural5-rules.txt'):
|
||||
pattern, search, replace = line.split(None, 3)
|
||||
yield build_match_and_apply_functions(pattern, search, replace)
|
||||
|
||||
def plural(noun):
|
||||
for matches_rule, apply_rule in rules():
|
||||
if matches_rule(noun):
|
||||
return apply_rule(noun)
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
if sys.argv[1:]:
|
||||
print(plural(sys.argv[1]))
|
||||
else:
|
||||
print(__doc__)
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,19 @@
|
||||
^(sheep|deer|fish|moose|aircraft|series|haiku)$ ($) \1
|
||||
[ml]ouse$ ouse$ ice
|
||||
child$ $ ren
|
||||
booth$ $ s
|
||||
foot$ oot$ eet
|
||||
ooth$ ooth$ eeth
|
||||
l[eo]af$ af$ aves
|
||||
sis$ sis$ ses
|
||||
^(hu|ro)man$ $ s
|
||||
man$ man$ men
|
||||
^lowlife$ $ s
|
||||
ife$ ife$ ives
|
||||
eau$ $ x
|
||||
^[dp]elf$ $ s
|
||||
lf$ lf$ lves
|
||||
[sxz]$ $ es
|
||||
[^aeioudgkprt]h$ $ es
|
||||
(qu|[^aeiou])y$ y$ ies
|
||||
$ $ s
|
||||
@@ -0,0 +1,80 @@
|
||||
"""Pluralize English nouns (stage 6)
|
||||
|
||||
Command line usage:
|
||||
$ python plural6.py noun
|
||||
nouns
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
def build_match_and_apply_functions(pattern, search, replace):
|
||||
def matches_rule(word):
|
||||
return re.search(pattern, word)
|
||||
def apply_rule(word):
|
||||
return re.sub(search, replace, word)
|
||||
return (matches_rule, apply_rule)
|
||||
|
||||
class LazyRules:
|
||||
def __init__(self):
|
||||
self.pattern_file = open('plural6-rules.txt')
|
||||
self.cache = []
|
||||
|
||||
def __iter__(self):
|
||||
self.cache_index = 0
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
self.cache_index += 1
|
||||
if len(self.cache) >= self.cache_index:
|
||||
return self.cache[self.cache_index - 1]
|
||||
|
||||
if self.pattern_file.closed:
|
||||
raise StopIteration
|
||||
|
||||
line = self.pattern_file.readline()
|
||||
if not line:
|
||||
self.pattern_file.close()
|
||||
raise StopIteration
|
||||
|
||||
pattern, search, replace = line.split(None, 3)
|
||||
funcs = build_match_and_apply_functions(
|
||||
pattern, search, replace)
|
||||
self.cache.append(funcs)
|
||||
return funcs
|
||||
|
||||
rules = LazyRules()
|
||||
|
||||
def plural(noun):
|
||||
for matches_rule, apply_rule in rules:
|
||||
if matches_rule(noun):
|
||||
return apply_rule(noun)
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
if sys.argv[1:]:
|
||||
print(plural(sys.argv[1]))
|
||||
else:
|
||||
print(__doc__)
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,81 @@
|
||||
"""Unit test for plural1.py"""
|
||||
|
||||
import plural1
|
||||
import unittest
|
||||
|
||||
class KnownValues(unittest.TestCase):
|
||||
def test_sxz(self):
|
||||
"words ending in S, X, and Z"
|
||||
nouns = {
|
||||
'bass': 'basses',
|
||||
'bus': 'buses',
|
||||
'walrus': 'walruses',
|
||||
'box': 'boxes',
|
||||
'fax': 'faxes',
|
||||
'suffix': 'suffixes',
|
||||
'mailbox': 'mailboxes',
|
||||
'buzz': 'buzzes',
|
||||
'waltz': 'waltzes'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural1.plural(singular), plural)
|
||||
|
||||
def test_h(self):
|
||||
"words ending in H"
|
||||
nouns = {
|
||||
'coach': 'coaches',
|
||||
'glitch': 'glitches',
|
||||
'rash': 'rashes',
|
||||
'watch': 'watches',
|
||||
'cheetah': 'cheetahs',
|
||||
'cough': 'coughs'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural1.plural(singular), plural)
|
||||
|
||||
def test_y(self):
|
||||
"words ending in Y"
|
||||
nouns = {
|
||||
'utility': 'utilities',
|
||||
'vacancy': 'vacancies',
|
||||
'boy': 'boys',
|
||||
'day': 'days'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural1.plural(singular), plural)
|
||||
|
||||
def test_default(self):
|
||||
"unexceptional words"
|
||||
nouns = {
|
||||
'papaya': 'papayas',
|
||||
'whip': 'whips',
|
||||
'palimpsest': 'palimpsests'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural1.plural(singular), plural)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,73 @@
|
||||
"""Unit test for plural2.py
|
||||
|
||||
This program is part of "Dive Into Python", a free Python book for
|
||||
experienced programmers. Visit http://diveintopython.org/ for the
|
||||
latest version.
|
||||
"""
|
||||
|
||||
__author__ = "Mark Pilgrim (mark@diveintopython.org)"
|
||||
__version__ = "$Revision: 1.2 $"
|
||||
__date__ = "$Date: 2004/03/17 14:34:40 $"
|
||||
__copyright__ = "Copyright (c) 2004 Mark Pilgrim"
|
||||
__license__ = "Python"
|
||||
|
||||
from plural2 import plural
|
||||
import unittest, new
|
||||
|
||||
class KnownValues(unittest.TestCase):
|
||||
nouns = {'bass': 'basses',
|
||||
'bus': 'buses',
|
||||
'walrus': 'walruses',
|
||||
'box': 'boxes',
|
||||
'fax': 'faxes',
|
||||
'suffix': 'suffixes',
|
||||
'mailbox': 'mailboxes',
|
||||
'buzz': 'buzzes',
|
||||
'waltz': 'waltzes',
|
||||
'coach': 'coaches',
|
||||
'glitch': 'glitches',
|
||||
'rash': 'rashes',
|
||||
'watch': 'watches',
|
||||
'cheetah': 'cheetahs',
|
||||
'cough': 'coughs',
|
||||
'utility': 'utilities',
|
||||
'vacancy': 'vacancies',
|
||||
'boy': 'boys',
|
||||
'day': 'days',
|
||||
'computer': 'computers',
|
||||
'rock': 'rocks',
|
||||
'paper': 'papers',
|
||||
}
|
||||
|
||||
for noun, pluralnoun in KnownValues.nouns.items():
|
||||
func = lambda self, noun=noun, pluralnoun=pluralnoun: \
|
||||
KnownValues.failUnlessEqual(self, plural(noun), pluralnoun)
|
||||
func.__doc__ = "%s --> %s" % (noun, pluralnoun)
|
||||
instanceMethod = new.instancemethod(func, None, KnownValues)
|
||||
setattr(KnownValues, "test_%s" % noun, instanceMethod)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,81 @@
|
||||
"""Unit test for plural1.py"""
|
||||
|
||||
import plural3
|
||||
import unittest
|
||||
|
||||
class KnownValues(unittest.TestCase):
|
||||
def test_sxz(self):
|
||||
"words ending in S, X, and Z"
|
||||
nouns = {
|
||||
'bass': 'basses',
|
||||
'bus': 'buses',
|
||||
'walrus': 'walruses',
|
||||
'box': 'boxes',
|
||||
'fax': 'faxes',
|
||||
'suffix': 'suffixes',
|
||||
'mailbox': 'mailboxes',
|
||||
'buzz': 'buzzes',
|
||||
'waltz': 'waltzes'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural3.plural(singular), plural)
|
||||
|
||||
def test_h(self):
|
||||
"words ending in H"
|
||||
nouns = {
|
||||
'coach': 'coaches',
|
||||
'glitch': 'glitches',
|
||||
'rash': 'rashes',
|
||||
'watch': 'watches',
|
||||
'cheetah': 'cheetahs',
|
||||
'cough': 'coughs'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural3.plural(singular), plural)
|
||||
|
||||
def test_y(self):
|
||||
"words ending in Y"
|
||||
nouns = {
|
||||
'utility': 'utilities',
|
||||
'vacancy': 'vacancies',
|
||||
'boy': 'boys',
|
||||
'day': 'days'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural3.plural(singular), plural)
|
||||
|
||||
def test_default(self):
|
||||
"unexceptional words"
|
||||
nouns = {
|
||||
'papaya': 'papayas',
|
||||
'whip': 'whips',
|
||||
'palimpsest': 'palimpsests'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural3.plural(singular), plural)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,81 @@
|
||||
"""Unit test for plural1.py"""
|
||||
|
||||
import plural4
|
||||
import unittest
|
||||
|
||||
class KnownValues(unittest.TestCase):
|
||||
def test_sxz(self):
|
||||
"words ending in S, X, and Z"
|
||||
nouns = {
|
||||
'bass': 'basses',
|
||||
'bus': 'buses',
|
||||
'walrus': 'walruses',
|
||||
'box': 'boxes',
|
||||
'fax': 'faxes',
|
||||
'suffix': 'suffixes',
|
||||
'mailbox': 'mailboxes',
|
||||
'buzz': 'buzzes',
|
||||
'waltz': 'waltzes'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural4.plural(singular), plural)
|
||||
|
||||
def test_h(self):
|
||||
"words ending in H"
|
||||
nouns = {
|
||||
'coach': 'coaches',
|
||||
'glitch': 'glitches',
|
||||
'rash': 'rashes',
|
||||
'watch': 'watches',
|
||||
'cheetah': 'cheetahs',
|
||||
'cough': 'coughs'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural4.plural(singular), plural)
|
||||
|
||||
def test_y(self):
|
||||
"words ending in Y"
|
||||
nouns = {
|
||||
'utility': 'utilities',
|
||||
'vacancy': 'vacancies',
|
||||
'boy': 'boys',
|
||||
'day': 'days'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural4.plural(singular), plural)
|
||||
|
||||
def test_default(self):
|
||||
"unexceptional words"
|
||||
nouns = {
|
||||
'papaya': 'papayas',
|
||||
'whip': 'whips',
|
||||
'palimpsest': 'palimpsests'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural4.plural(singular), plural)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,84 @@
|
||||
"""Unit test for plural5.py"""
|
||||
|
||||
import plural5
|
||||
import unittest
|
||||
|
||||
class KnownValues(unittest.TestCase):
|
||||
def test_sxz(self):
|
||||
"words ending in S, X, and Z"
|
||||
nouns = {
|
||||
'bass': 'basses',
|
||||
'bus': 'buses',
|
||||
'walrus': 'walruses',
|
||||
'box': 'boxes',
|
||||
'fax': 'faxes',
|
||||
'suffix': 'suffixes',
|
||||
'mailbox': 'mailboxes',
|
||||
'buzz': 'buzzes',
|
||||
'waltz': 'waltzes'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural5.plural(singular), plural)
|
||||
|
||||
def test_h(self):
|
||||
"words ending in H"
|
||||
nouns = {
|
||||
'coach': 'coaches',
|
||||
'glitch': 'glitches',
|
||||
'rash': 'rashes',
|
||||
'watch': 'watches',
|
||||
'cheetah': 'cheetahs',
|
||||
'cough': 'coughs'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural5.plural(singular), plural)
|
||||
|
||||
def test_y(self):
|
||||
"words ending in Y"
|
||||
nouns = {
|
||||
'utility': 'utilities',
|
||||
'vacancy': 'vacancies',
|
||||
'boy': 'boys',
|
||||
'day': 'days'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural5.plural(singular), plural)
|
||||
|
||||
def test_default(self):
|
||||
"unexceptional words"
|
||||
nouns = {
|
||||
'papaya': 'papayas',
|
||||
'whip': 'whips',
|
||||
'palimpsest': 'palimpsests'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural5.plural(singular), plural)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,189 @@
|
||||
"""Unit test for plural6.py"""
|
||||
|
||||
import plural6
|
||||
import unittest
|
||||
|
||||
class KnownValues(unittest.TestCase):
|
||||
def test_sxz(self):
|
||||
"words ending in S, X, and Z"
|
||||
nouns = {
|
||||
'bass': 'basses',
|
||||
'bus': 'buses',
|
||||
'walrus': 'walruses',
|
||||
'box': 'boxes',
|
||||
'fax': 'faxes',
|
||||
'suffix': 'suffixes',
|
||||
'mailbox': 'mailboxes',
|
||||
'buzz': 'buzzes',
|
||||
'waltz': 'waltzes'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural6.plural(singular), plural)
|
||||
|
||||
def test_h(self):
|
||||
"words ending in H"
|
||||
nouns = {
|
||||
'coach': 'coaches',
|
||||
'glitch': 'glitches',
|
||||
'rash': 'rashes',
|
||||
'watch': 'watches',
|
||||
'cheetah': 'cheetahs',
|
||||
'cough': 'coughs'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural6.plural(singular), plural)
|
||||
|
||||
def test_y(self):
|
||||
"words ending in Y"
|
||||
nouns = {
|
||||
'utility': 'utilities',
|
||||
'vacancy': 'vacancies',
|
||||
'boy': 'boys',
|
||||
'day': 'days'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural6.plural(singular), plural)
|
||||
|
||||
def test_ouce(self):
|
||||
"words ending in OUSE"
|
||||
nouns = {
|
||||
'mouse': 'mice',
|
||||
'louse': 'lice'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural6.plural(singular), plural)
|
||||
|
||||
def test_child(self):
|
||||
"special case: child"
|
||||
nouns = {
|
||||
'child': 'children'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural6.plural(singular), plural)
|
||||
|
||||
def test_oot(self):
|
||||
"special case: foot"
|
||||
nouns = {
|
||||
'foot': 'feet'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural6.plural(singular), plural)
|
||||
|
||||
def test_ooth(self):
|
||||
"words ending in OOTH"
|
||||
nouns = {
|
||||
'booth': 'booths',
|
||||
'tooth': 'teeth'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural6.plural(singular), plural)
|
||||
|
||||
def test_f_ves(self):
|
||||
"words ending in F that become VES"
|
||||
nouns = {
|
||||
'leaf': 'leaves',
|
||||
'loaf': 'loaves'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural6.plural(singular), plural)
|
||||
|
||||
def test_sis(self):
|
||||
"words ending in SIS"
|
||||
nouns = {
|
||||
'thesis': 'theses'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural6.plural(singular), plural)
|
||||
|
||||
def test_man(self):
|
||||
"words ending in MAN"
|
||||
nouns = {
|
||||
'man': 'men',
|
||||
'mailman': 'mailmen',
|
||||
'human': 'humans',
|
||||
'roman': 'romans'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural6.plural(singular), plural)
|
||||
|
||||
def test_ife(self):
|
||||
"words ending in IFE"
|
||||
nouns = {
|
||||
'knife': 'knives',
|
||||
'wife': 'wives',
|
||||
'lowlife': 'lowlifes'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural6.plural(singular), plural)
|
||||
|
||||
def test_eau(self):
|
||||
"words ending in EAU"
|
||||
nouns = {
|
||||
'tableau': 'tableaux'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural6.plural(singular), plural)
|
||||
|
||||
def test_elf(self):
|
||||
"words ending in ELF"
|
||||
nouns = {
|
||||
'elf': 'elves',
|
||||
'shelf': 'shelves',
|
||||
'delf': 'delfs',
|
||||
'pelf': 'pelfs'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural6.plural(singular), plural)
|
||||
|
||||
def test_same(self):
|
||||
"words that are their own plural"
|
||||
nouns = {
|
||||
'sheep': 'sheep',
|
||||
'deer': 'deer',
|
||||
'fish': 'fish',
|
||||
'moose': 'moose',
|
||||
'aircraft': 'aircraft',
|
||||
'series': 'series',
|
||||
'haiku': 'haiku'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural6.plural(singular), plural)
|
||||
|
||||
def test_default(self):
|
||||
"unexceptional words"
|
||||
nouns = {
|
||||
'papaya': 'papayas',
|
||||
'whip': 'whips',
|
||||
'palimpsest': 'palimpsests'
|
||||
}
|
||||
for singular, plural in nouns.items():
|
||||
self.assertEqual(plural6.plural(singular), plural)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,52 @@
|
||||
"""Convert to and from Roman numerals
|
||||
|
||||
This program is part of "Dive Into Python 3", a free Python book for
|
||||
experienced programmers. Visit http://diveintopython3.org/ for the
|
||||
latest version.
|
||||
"""
|
||||
|
||||
roman_numeral_map = (('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 to_roman(n):
|
||||
"""convert integer to Roman numeral"""
|
||||
result = ""
|
||||
for numeral, integer in roman_numeral_map:
|
||||
while n >= integer:
|
||||
result += numeral
|
||||
n -= integer
|
||||
return result
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,57 @@
|
||||
"""Convert to and from Roman numerals
|
||||
|
||||
This program is part of "Dive Into Python 3", a free Python book for
|
||||
experienced programmers. Visit http://diveintopython3.org/ for the
|
||||
latest version.
|
||||
"""
|
||||
class OutOfRangeError(ValueError):
|
||||
pass
|
||||
|
||||
roman_numeral_map = (('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 to_roman(n):
|
||||
"""convert integer to Roman numeral"""
|
||||
if n > 3999:
|
||||
raise OutOfRangeError("number out of range (must be less than 3999)")
|
||||
|
||||
result = ""
|
||||
for numeral, integer in roman_numeral_map:
|
||||
while n >= integer:
|
||||
result += numeral
|
||||
n -= integer
|
||||
return result
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,56 @@
|
||||
"""Convert to and from Roman numerals
|
||||
|
||||
This program is part of "Dive Into Python 3", a free Python book for
|
||||
experienced programmers. Visit http://diveintopython3.org/ for the
|
||||
latest version.
|
||||
"""
|
||||
class OutOfRangeError(ValueError): pass
|
||||
|
||||
roman_numeral_map = (('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 to_roman(n):
|
||||
"""convert integer to Roman numeral"""
|
||||
if not (0 < n < 4000):
|
||||
raise OutOfRangeError("number out of range (must be 0..3999)")
|
||||
|
||||
result = ""
|
||||
for numeral, integer in roman_numeral_map:
|
||||
while n >= integer:
|
||||
result += numeral
|
||||
n -= integer
|
||||
return result
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,59 @@
|
||||
"""Convert to and from Roman numerals
|
||||
|
||||
This program is part of "Dive Into Python 3", a free Python book for
|
||||
experienced programmers. Visit http://diveintopython3.org/ for the
|
||||
latest version.
|
||||
"""
|
||||
class OutOfRangeError(ValueError): pass
|
||||
class NotIntegerError(ValueError): pass
|
||||
|
||||
roman_numeral_map = (('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 to_roman(n):
|
||||
"""convert integer to Roman numeral"""
|
||||
if not (0 < n < 4000):
|
||||
raise OutOfRangeError("number out of range (must be 0..3999)")
|
||||
if not isinstance(n, int):
|
||||
raise NotIntegerError("non-integers can not be converted")
|
||||
|
||||
result = ""
|
||||
for numeral, integer in roman_numeral_map:
|
||||
while n >= integer:
|
||||
result += numeral
|
||||
n -= integer
|
||||
return result
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,69 @@
|
||||
"""Convert to and from Roman numerals
|
||||
|
||||
This program is part of "Dive Into Python 3", a free Python book for
|
||||
experienced programmers. Visit http://diveintopython3.org/ for the
|
||||
latest version.
|
||||
"""
|
||||
class OutOfRangeError(ValueError): pass
|
||||
class NotIntegerError(ValueError): pass
|
||||
|
||||
roman_numeral_map = (('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 to_roman(n):
|
||||
"""convert integer to Roman numeral"""
|
||||
if not (0 < n < 4000):
|
||||
raise OutOfRangeError("number out of range (must be 0..3999)")
|
||||
if not isinstance(n, int):
|
||||
raise NotIntegerError("non-integers can not be converted")
|
||||
|
||||
result = ""
|
||||
for numeral, integer in roman_numeral_map:
|
||||
while n >= integer:
|
||||
result += numeral
|
||||
n -= integer
|
||||
return result
|
||||
|
||||
def from_roman(s):
|
||||
"""convert Roman numeral to integer"""
|
||||
result = 0
|
||||
index = 0
|
||||
for numeral, integer in roman_numeral_map:
|
||||
while s[index : index + len(numeral)] == numeral:
|
||||
result += integer
|
||||
index += len(numeral)
|
||||
return result
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,87 @@
|
||||
"""Convert to and from Roman numerals
|
||||
|
||||
This program is part of "Dive Into Python 3", a free Python book for
|
||||
experienced programmers. Visit http://diveintopython3.org/ for the
|
||||
latest version.
|
||||
"""
|
||||
import re
|
||||
|
||||
class OutOfRangeError(ValueError): pass
|
||||
class NotIntegerError(ValueError): pass
|
||||
class InvalidRomanNumeralError(ValueError): pass
|
||||
|
||||
roman_numeral_map = (('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))
|
||||
|
||||
roman_numeral_pattern = re.compile("""
|
||||
^ # beginning of string
|
||||
M{0,3} # thousands - 0 to 3 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 to_roman(n):
|
||||
"""convert integer to Roman numeral"""
|
||||
if not (0 < n < 4000):
|
||||
raise OutOfRangeError("number out of range (must be 0..3999)")
|
||||
if not isinstance(n, int):
|
||||
raise NotIntegerError("non-integers can not be converted")
|
||||
|
||||
result = ""
|
||||
for numeral, integer in roman_numeral_map:
|
||||
while n >= integer:
|
||||
result += numeral
|
||||
n -= integer
|
||||
return result
|
||||
|
||||
def from_roman(s):
|
||||
"""convert Roman numeral to integer"""
|
||||
if not roman_numeral_pattern.search(s):
|
||||
raise InvalidRomanNumeralError("Invalid Roman numeral: {0}".format(s))
|
||||
|
||||
result = 0
|
||||
index = 0
|
||||
for numeral, integer in roman_numeral_map:
|
||||
while s[index : index + len(numeral)] == numeral:
|
||||
result += integer
|
||||
index += len(numeral)
|
||||
return result
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,89 @@
|
||||
"""Convert to and from Roman numerals
|
||||
|
||||
This program is part of "Dive Into Python 3", a free Python book for
|
||||
experienced programmers. Visit http://diveintopython3.org/ for the
|
||||
latest version.
|
||||
"""
|
||||
import re
|
||||
|
||||
class OutOfRangeError(ValueError): pass
|
||||
class NotIntegerError(ValueError): pass
|
||||
class InvalidRomanNumeralError(ValueError): pass
|
||||
|
||||
roman_numeral_map = (('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))
|
||||
|
||||
roman_numeral_pattern = re.compile("""
|
||||
^ # beginning of string
|
||||
M{0,3} # thousands - 0 to 3 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 to_roman(n):
|
||||
"""convert integer to Roman numeral"""
|
||||
if not (0 < n < 4000):
|
||||
raise OutOfRangeError("number out of range (must be 0..3999)")
|
||||
if not isinstance(n, int):
|
||||
raise NotIntegerError("non-integers can not be converted")
|
||||
|
||||
result = ""
|
||||
for numeral, integer in roman_numeral_map:
|
||||
while n >= integer:
|
||||
result += numeral
|
||||
n -= integer
|
||||
return result
|
||||
|
||||
def from_roman(s):
|
||||
"""convert Roman numeral to integer"""
|
||||
if not s:
|
||||
raise InvalidRomanNumeralError("Input can not be blank")
|
||||
if not roman_numeral_pattern.search(s):
|
||||
raise InvalidRomanNumeralError("Invalid Roman numeral: {0}".format(s))
|
||||
|
||||
result = 0
|
||||
index = 0
|
||||
for numeral, integer in roman_numeral_map:
|
||||
while s[index : index + len(numeral)] == numeral:
|
||||
result += integer
|
||||
index += len(numeral)
|
||||
return result
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,91 @@
|
||||
"""Convert to and from Roman numerals
|
||||
|
||||
This program is part of "Dive Into Python 3", a free Python book for
|
||||
experienced programmers. Visit http://diveintopython3.org/ for the
|
||||
latest version.
|
||||
"""
|
||||
import re
|
||||
|
||||
class OutOfRangeError(ValueError): pass
|
||||
class NotIntegerError(ValueError): pass
|
||||
class InvalidRomanNumeralError(ValueError): pass
|
||||
|
||||
roman_numeral_map = (('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))
|
||||
|
||||
roman_numeral_pattern = re.compile("""
|
||||
^ # beginning of string
|
||||
M{0,3} # thousands - 0 to 3 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 to_roman(n):
|
||||
"""convert integer to Roman numeral"""
|
||||
if not (0 < n < 4000):
|
||||
raise OutOfRangeError("number out of range (must be 0..3999)")
|
||||
if not isinstance(n, int):
|
||||
raise NotIntegerError("non-integers can not be converted")
|
||||
|
||||
result = ""
|
||||
for numeral, integer in roman_numeral_map:
|
||||
while n >= integer:
|
||||
result += numeral
|
||||
n -= integer
|
||||
return result
|
||||
|
||||
def from_roman(s):
|
||||
"""convert Roman numeral to integer"""
|
||||
if not isinstance(s, str):
|
||||
raise InvalidRomanNumeralError("Input must be a string")
|
||||
if not s:
|
||||
raise InvalidRomanNumeralError("Input can not be blank")
|
||||
if not roman_numeral_pattern.search(s):
|
||||
raise InvalidRomanNumeralError("Invalid Roman numeral: {0}".format(s))
|
||||
|
||||
result = 0
|
||||
index = 0
|
||||
for numeral, integer in roman_numeral_map:
|
||||
while s[index : index + len(numeral)] == numeral:
|
||||
result += integer
|
||||
index += len(numeral)
|
||||
return result
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,99 @@
|
||||
"""Unit test for roman1.py
|
||||
|
||||
This program is part of "Dive Into Python 3", a free Python book for
|
||||
experienced programmers. Visit http://diveintopython3.org/ for the
|
||||
latest version.
|
||||
"""
|
||||
|
||||
import roman1
|
||||
import unittest
|
||||
|
||||
class KnownValues(unittest.TestCase):
|
||||
known_values = ( (1, 'I'),
|
||||
(2, 'II'),
|
||||
(3, 'III'),
|
||||
(4, 'IV'),
|
||||
(5, 'V'),
|
||||
(6, 'VI'),
|
||||
(7, 'VII'),
|
||||
(8, 'VIII'),
|
||||
(9, 'IX'),
|
||||
(10, 'X'),
|
||||
(50, 'L'),
|
||||
(100, 'C'),
|
||||
(500, 'D'),
|
||||
(1000, 'M'),
|
||||
(31, 'XXXI'),
|
||||
(148, 'CXLVIII'),
|
||||
(294, 'CCXCIV'),
|
||||
(312, 'CCCXII'),
|
||||
(421, 'CDXXI'),
|
||||
(528, 'DXXVIII'),
|
||||
(621, 'DCXXI'),
|
||||
(782, 'DCCLXXXII'),
|
||||
(870, 'DCCCLXX'),
|
||||
(941, 'CMXLI'),
|
||||
(1043, 'MXLIII'),
|
||||
(1110, 'MCX'),
|
||||
(1226, 'MCCXXVI'),
|
||||
(1301, 'MCCCI'),
|
||||
(1485, 'MCDLXXXV'),
|
||||
(1509, 'MDIX'),
|
||||
(1607, 'MDCVII'),
|
||||
(1754, 'MDCCLIV'),
|
||||
(1832, 'MDCCCXXXII'),
|
||||
(1993, 'MCMXCIII'),
|
||||
(2074, 'MMLXXIV'),
|
||||
(2152, 'MMCLII'),
|
||||
(2212, 'MMCCXII'),
|
||||
(2343, 'MMCCCXLIII'),
|
||||
(2499, 'MMCDXCIX'),
|
||||
(2574, 'MMDLXXIV'),
|
||||
(2646, 'MMDCXLVI'),
|
||||
(2723, 'MMDCCXXIII'),
|
||||
(2892, 'MMDCCCXCII'),
|
||||
(2975, 'MMCMLXXV'),
|
||||
(3051, 'MMMLI'),
|
||||
(3185, 'MMMCLXXXV'),
|
||||
(3250, 'MMMCCL'),
|
||||
(3313, 'MMMCCCXIII'),
|
||||
(3408, 'MMMCDVIII'),
|
||||
(3501, 'MMMDI'),
|
||||
(3610, 'MMMDCX'),
|
||||
(3743, 'MMMDCCXLIII'),
|
||||
(3844, 'MMMDCCCXLIV'),
|
||||
(3888, 'MMMDCCCLXXXVIII'),
|
||||
(3940, 'MMMCMXL'),
|
||||
(3999, 'MMMCMXCIX'))
|
||||
|
||||
def test_to_roman_known_values(self):
|
||||
"""to_roman should give known result with known input"""
|
||||
for integer, numeral in self.known_values:
|
||||
result = roman1.to_roman(integer)
|
||||
self.assertEqual(numeral, result)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,104 @@
|
||||
"""Unit test for roman1.py
|
||||
|
||||
This program is part of "Dive Into Python 3", a free Python book for
|
||||
experienced programmers. Visit http://diveintopython3.org/ for the
|
||||
latest version.
|
||||
"""
|
||||
|
||||
import roman2
|
||||
import unittest
|
||||
|
||||
class KnownValues(unittest.TestCase):
|
||||
known_values = ( (1, 'I'),
|
||||
(2, 'II'),
|
||||
(3, 'III'),
|
||||
(4, 'IV'),
|
||||
(5, 'V'),
|
||||
(6, 'VI'),
|
||||
(7, 'VII'),
|
||||
(8, 'VIII'),
|
||||
(9, 'IX'),
|
||||
(10, 'X'),
|
||||
(50, 'L'),
|
||||
(100, 'C'),
|
||||
(500, 'D'),
|
||||
(1000, 'M'),
|
||||
(31, 'XXXI'),
|
||||
(148, 'CXLVIII'),
|
||||
(294, 'CCXCIV'),
|
||||
(312, 'CCCXII'),
|
||||
(421, 'CDXXI'),
|
||||
(528, 'DXXVIII'),
|
||||
(621, 'DCXXI'),
|
||||
(782, 'DCCLXXXII'),
|
||||
(870, 'DCCCLXX'),
|
||||
(941, 'CMXLI'),
|
||||
(1043, 'MXLIII'),
|
||||
(1110, 'MCX'),
|
||||
(1226, 'MCCXXVI'),
|
||||
(1301, 'MCCCI'),
|
||||
(1485, 'MCDLXXXV'),
|
||||
(1509, 'MDIX'),
|
||||
(1607, 'MDCVII'),
|
||||
(1754, 'MDCCLIV'),
|
||||
(1832, 'MDCCCXXXII'),
|
||||
(1993, 'MCMXCIII'),
|
||||
(2074, 'MMLXXIV'),
|
||||
(2152, 'MMCLII'),
|
||||
(2212, 'MMCCXII'),
|
||||
(2343, 'MMCCCXLIII'),
|
||||
(2499, 'MMCDXCIX'),
|
||||
(2574, 'MMDLXXIV'),
|
||||
(2646, 'MMDCXLVI'),
|
||||
(2723, 'MMDCCXXIII'),
|
||||
(2892, 'MMDCCCXCII'),
|
||||
(2975, 'MMCMLXXV'),
|
||||
(3051, 'MMMLI'),
|
||||
(3185, 'MMMCLXXXV'),
|
||||
(3250, 'MMMCCL'),
|
||||
(3313, 'MMMCCCXIII'),
|
||||
(3408, 'MMMCDVIII'),
|
||||
(3501, 'MMMDI'),
|
||||
(3610, 'MMMDCX'),
|
||||
(3743, 'MMMDCCXLIII'),
|
||||
(3844, 'MMMDCCCXLIV'),
|
||||
(3888, 'MMMDCCCLXXXVIII'),
|
||||
(3940, 'MMMCMXL'),
|
||||
(3999, 'MMMCMXCIX'))
|
||||
|
||||
def test_to_roman_known_values(self):
|
||||
"""to_roman should give known result with known input"""
|
||||
for integer, numeral in self.known_values:
|
||||
result = roman2.to_roman(integer)
|
||||
self.assertEqual(numeral, result)
|
||||
|
||||
class ToRomanBadInput(unittest.TestCase):
|
||||
def test_too_large(self):
|
||||
"""to_roman should fail with large input"""
|
||||
self.assertRaises(roman2.OutOfRangeError, roman2.to_roman, 4000)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,112 @@
|
||||
"""Unit test for roman1.py
|
||||
|
||||
This program is part of "Dive Into Python 3", a free Python book for
|
||||
experienced programmers. Visit http://diveintopython3.org/ for the
|
||||
latest version.
|
||||
"""
|
||||
|
||||
import roman3
|
||||
import unittest
|
||||
|
||||
class KnownValues(unittest.TestCase):
|
||||
known_values = ( (1, 'I'),
|
||||
(2, 'II'),
|
||||
(3, 'III'),
|
||||
(4, 'IV'),
|
||||
(5, 'V'),
|
||||
(6, 'VI'),
|
||||
(7, 'VII'),
|
||||
(8, 'VIII'),
|
||||
(9, 'IX'),
|
||||
(10, 'X'),
|
||||
(50, 'L'),
|
||||
(100, 'C'),
|
||||
(500, 'D'),
|
||||
(1000, 'M'),
|
||||
(31, 'XXXI'),
|
||||
(148, 'CXLVIII'),
|
||||
(294, 'CCXCIV'),
|
||||
(312, 'CCCXII'),
|
||||
(421, 'CDXXI'),
|
||||
(528, 'DXXVIII'),
|
||||
(621, 'DCXXI'),
|
||||
(782, 'DCCLXXXII'),
|
||||
(870, 'DCCCLXX'),
|
||||
(941, 'CMXLI'),
|
||||
(1043, 'MXLIII'),
|
||||
(1110, 'MCX'),
|
||||
(1226, 'MCCXXVI'),
|
||||
(1301, 'MCCCI'),
|
||||
(1485, 'MCDLXXXV'),
|
||||
(1509, 'MDIX'),
|
||||
(1607, 'MDCVII'),
|
||||
(1754, 'MDCCLIV'),
|
||||
(1832, 'MDCCCXXXII'),
|
||||
(1993, 'MCMXCIII'),
|
||||
(2074, 'MMLXXIV'),
|
||||
(2152, 'MMCLII'),
|
||||
(2212, 'MMCCXII'),
|
||||
(2343, 'MMCCCXLIII'),
|
||||
(2499, 'MMCDXCIX'),
|
||||
(2574, 'MMDLXXIV'),
|
||||
(2646, 'MMDCXLVI'),
|
||||
(2723, 'MMDCCXXIII'),
|
||||
(2892, 'MMDCCCXCII'),
|
||||
(2975, 'MMCMLXXV'),
|
||||
(3051, 'MMMLI'),
|
||||
(3185, 'MMMCLXXXV'),
|
||||
(3250, 'MMMCCL'),
|
||||
(3313, 'MMMCCCXIII'),
|
||||
(3408, 'MMMCDVIII'),
|
||||
(3501, 'MMMDI'),
|
||||
(3610, 'MMMDCX'),
|
||||
(3743, 'MMMDCCXLIII'),
|
||||
(3844, 'MMMDCCCXLIV'),
|
||||
(3888, 'MMMDCCCLXXXVIII'),
|
||||
(3940, 'MMMCMXL'),
|
||||
(3999, 'MMMCMXCIX'))
|
||||
|
||||
def test_to_roman_known_values(self):
|
||||
"""to_roman should give known result with known input"""
|
||||
for integer, numeral in self.known_values:
|
||||
result = roman3.to_roman(integer)
|
||||
self.assertEqual(numeral, result)
|
||||
|
||||
class ToRomanBadInput(unittest.TestCase):
|
||||
def test_too_large(self):
|
||||
"""to_roman should fail with large input"""
|
||||
self.assertRaises(roman3.OutOfRangeError, roman3.to_roman, 4000)
|
||||
|
||||
def test_zero(self):
|
||||
"""to_roman should fail with 0 input"""
|
||||
self.assertRaises(roman3.OutOfRangeError, roman3.to_roman, 0)
|
||||
|
||||
def test_negative(self):
|
||||
"""to_roman should fail with negative input"""
|
||||
self.assertRaises(roman3.OutOfRangeError, roman3.to_roman, -1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,116 @@
|
||||
"""Unit test for roman1.py
|
||||
|
||||
This program is part of "Dive Into Python 3", a free Python book for
|
||||
experienced programmers. Visit http://diveintopython3.org/ for the
|
||||
latest version.
|
||||
"""
|
||||
|
||||
import roman4
|
||||
import unittest
|
||||
|
||||
class KnownValues(unittest.TestCase):
|
||||
known_values = ( (1, 'I'),
|
||||
(2, 'II'),
|
||||
(3, 'III'),
|
||||
(4, 'IV'),
|
||||
(5, 'V'),
|
||||
(6, 'VI'),
|
||||
(7, 'VII'),
|
||||
(8, 'VIII'),
|
||||
(9, 'IX'),
|
||||
(10, 'X'),
|
||||
(50, 'L'),
|
||||
(100, 'C'),
|
||||
(500, 'D'),
|
||||
(1000, 'M'),
|
||||
(31, 'XXXI'),
|
||||
(148, 'CXLVIII'),
|
||||
(294, 'CCXCIV'),
|
||||
(312, 'CCCXII'),
|
||||
(421, 'CDXXI'),
|
||||
(528, 'DXXVIII'),
|
||||
(621, 'DCXXI'),
|
||||
(782, 'DCCLXXXII'),
|
||||
(870, 'DCCCLXX'),
|
||||
(941, 'CMXLI'),
|
||||
(1043, 'MXLIII'),
|
||||
(1110, 'MCX'),
|
||||
(1226, 'MCCXXVI'),
|
||||
(1301, 'MCCCI'),
|
||||
(1485, 'MCDLXXXV'),
|
||||
(1509, 'MDIX'),
|
||||
(1607, 'MDCVII'),
|
||||
(1754, 'MDCCLIV'),
|
||||
(1832, 'MDCCCXXXII'),
|
||||
(1993, 'MCMXCIII'),
|
||||
(2074, 'MMLXXIV'),
|
||||
(2152, 'MMCLII'),
|
||||
(2212, 'MMCCXII'),
|
||||
(2343, 'MMCCCXLIII'),
|
||||
(2499, 'MMCDXCIX'),
|
||||
(2574, 'MMDLXXIV'),
|
||||
(2646, 'MMDCXLVI'),
|
||||
(2723, 'MMDCCXXIII'),
|
||||
(2892, 'MMDCCCXCII'),
|
||||
(2975, 'MMCMLXXV'),
|
||||
(3051, 'MMMLI'),
|
||||
(3185, 'MMMCLXXXV'),
|
||||
(3250, 'MMMCCL'),
|
||||
(3313, 'MMMCCCXIII'),
|
||||
(3408, 'MMMCDVIII'),
|
||||
(3501, 'MMMDI'),
|
||||
(3610, 'MMMDCX'),
|
||||
(3743, 'MMMDCCXLIII'),
|
||||
(3844, 'MMMDCCCXLIV'),
|
||||
(3888, 'MMMDCCCLXXXVIII'),
|
||||
(3940, 'MMMCMXL'),
|
||||
(3999, 'MMMCMXCIX'))
|
||||
|
||||
def test_to_roman_known_values(self):
|
||||
"""to_roman should give known result with known input"""
|
||||
for integer, numeral in self.known_values:
|
||||
result = roman4.to_roman(integer)
|
||||
self.assertEqual(numeral, result)
|
||||
|
||||
class ToRomanBadInput(unittest.TestCase):
|
||||
def test_too_large(self):
|
||||
"""to_roman should fail with large input"""
|
||||
self.assertRaises(roman4.OutOfRangeError, roman4.to_roman, 4000)
|
||||
|
||||
def test_zero(self):
|
||||
"""to_roman should fail with 0 input"""
|
||||
self.assertRaises(roman4.OutOfRangeError, roman4.to_roman, 0)
|
||||
|
||||
def test_negative(self):
|
||||
"""to_roman should fail with negative input"""
|
||||
self.assertRaises(roman4.OutOfRangeError, roman4.to_roman, -1)
|
||||
|
||||
def test_non_integer(self):
|
||||
"""to_roman should fail with non-integer input"""
|
||||
self.assertRaises(roman4.NotIntegerError, roman4.to_roman, 0.5)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,130 @@
|
||||
"""Unit test for roman1.py
|
||||
|
||||
This program is part of "Dive Into Python 3", a free Python book for
|
||||
experienced programmers. Visit http://diveintopython3.org/ for the
|
||||
latest version.
|
||||
"""
|
||||
|
||||
import roman5
|
||||
import unittest
|
||||
|
||||
class KnownValues(unittest.TestCase):
|
||||
known_values = ( (1, 'I'),
|
||||
(2, 'II'),
|
||||
(3, 'III'),
|
||||
(4, 'IV'),
|
||||
(5, 'V'),
|
||||
(6, 'VI'),
|
||||
(7, 'VII'),
|
||||
(8, 'VIII'),
|
||||
(9, 'IX'),
|
||||
(10, 'X'),
|
||||
(50, 'L'),
|
||||
(100, 'C'),
|
||||
(500, 'D'),
|
||||
(1000, 'M'),
|
||||
(31, 'XXXI'),
|
||||
(148, 'CXLVIII'),
|
||||
(294, 'CCXCIV'),
|
||||
(312, 'CCCXII'),
|
||||
(421, 'CDXXI'),
|
||||
(528, 'DXXVIII'),
|
||||
(621, 'DCXXI'),
|
||||
(782, 'DCCLXXXII'),
|
||||
(870, 'DCCCLXX'),
|
||||
(941, 'CMXLI'),
|
||||
(1043, 'MXLIII'),
|
||||
(1110, 'MCX'),
|
||||
(1226, 'MCCXXVI'),
|
||||
(1301, 'MCCCI'),
|
||||
(1485, 'MCDLXXXV'),
|
||||
(1509, 'MDIX'),
|
||||
(1607, 'MDCVII'),
|
||||
(1754, 'MDCCLIV'),
|
||||
(1832, 'MDCCCXXXII'),
|
||||
(1993, 'MCMXCIII'),
|
||||
(2074, 'MMLXXIV'),
|
||||
(2152, 'MMCLII'),
|
||||
(2212, 'MMCCXII'),
|
||||
(2343, 'MMCCCXLIII'),
|
||||
(2499, 'MMCDXCIX'),
|
||||
(2574, 'MMDLXXIV'),
|
||||
(2646, 'MMDCXLVI'),
|
||||
(2723, 'MMDCCXXIII'),
|
||||
(2892, 'MMDCCCXCII'),
|
||||
(2975, 'MMCMLXXV'),
|
||||
(3051, 'MMMLI'),
|
||||
(3185, 'MMMCLXXXV'),
|
||||
(3250, 'MMMCCL'),
|
||||
(3313, 'MMMCCCXIII'),
|
||||
(3408, 'MMMCDVIII'),
|
||||
(3501, 'MMMDI'),
|
||||
(3610, 'MMMDCX'),
|
||||
(3743, 'MMMDCCXLIII'),
|
||||
(3844, 'MMMDCCCXLIV'),
|
||||
(3888, 'MMMDCCCLXXXVIII'),
|
||||
(3940, 'MMMCMXL'),
|
||||
(3999, 'MMMCMXCIX'))
|
||||
|
||||
def test_to_roman_known_values(self):
|
||||
"""to_roman should give known result with known input"""
|
||||
for integer, numeral in self.known_values:
|
||||
result = roman5.to_roman(integer)
|
||||
self.assertEqual(numeral, result)
|
||||
|
||||
def test_from_roman_known_values(self):
|
||||
"""from_roman should give known result with known input"""
|
||||
for integer, numeral in self.known_values:
|
||||
result = roman5.from_roman(numeral)
|
||||
self.assertEqual(integer, result)
|
||||
|
||||
class ToRomanBadInput(unittest.TestCase):
|
||||
def test_too_large(self):
|
||||
"""to_roman should fail with large input"""
|
||||
self.assertRaises(roman5.OutOfRangeError, roman5.to_roman, 4000)
|
||||
|
||||
def test_zero(self):
|
||||
"""to_roman should fail with 0 input"""
|
||||
self.assertRaises(roman5.OutOfRangeError, roman5.to_roman, 0)
|
||||
|
||||
def test_negative(self):
|
||||
"""to_roman should fail with negative input"""
|
||||
self.assertRaises(roman5.OutOfRangeError, roman5.to_roman, -1)
|
||||
|
||||
def test_non_integer(self):
|
||||
"""to_roman should fail with non-integer input"""
|
||||
self.assertRaises(roman5.NotIntegerError, roman5.to_roman, 0.5)
|
||||
|
||||
class SanityCheck(unittest.TestCase):
|
||||
def testSanity(self):
|
||||
"""from_roman(to_roman(n))==n for all n"""
|
||||
for integer in range(1, 4000):
|
||||
numeral = roman5.to_roman(integer)
|
||||
result = roman5.from_roman(numeral)
|
||||
self.assertEqual(integer, result)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,147 @@
|
||||
"""Unit test for roman1.py
|
||||
|
||||
This program is part of "Dive Into Python 3", a free Python book for
|
||||
experienced programmers. Visit http://diveintopython3.org/ for the
|
||||
latest version.
|
||||
"""
|
||||
|
||||
import roman6
|
||||
import unittest
|
||||
|
||||
class KnownValues(unittest.TestCase):
|
||||
known_values = ( (1, 'I'),
|
||||
(2, 'II'),
|
||||
(3, 'III'),
|
||||
(4, 'IV'),
|
||||
(5, 'V'),
|
||||
(6, 'VI'),
|
||||
(7, 'VII'),
|
||||
(8, 'VIII'),
|
||||
(9, 'IX'),
|
||||
(10, 'X'),
|
||||
(50, 'L'),
|
||||
(100, 'C'),
|
||||
(500, 'D'),
|
||||
(1000, 'M'),
|
||||
(31, 'XXXI'),
|
||||
(148, 'CXLVIII'),
|
||||
(294, 'CCXCIV'),
|
||||
(312, 'CCCXII'),
|
||||
(421, 'CDXXI'),
|
||||
(528, 'DXXVIII'),
|
||||
(621, 'DCXXI'),
|
||||
(782, 'DCCLXXXII'),
|
||||
(870, 'DCCCLXX'),
|
||||
(941, 'CMXLI'),
|
||||
(1043, 'MXLIII'),
|
||||
(1110, 'MCX'),
|
||||
(1226, 'MCCXXVI'),
|
||||
(1301, 'MCCCI'),
|
||||
(1485, 'MCDLXXXV'),
|
||||
(1509, 'MDIX'),
|
||||
(1607, 'MDCVII'),
|
||||
(1754, 'MDCCLIV'),
|
||||
(1832, 'MDCCCXXXII'),
|
||||
(1993, 'MCMXCIII'),
|
||||
(2074, 'MMLXXIV'),
|
||||
(2152, 'MMCLII'),
|
||||
(2212, 'MMCCXII'),
|
||||
(2343, 'MMCCCXLIII'),
|
||||
(2499, 'MMCDXCIX'),
|
||||
(2574, 'MMDLXXIV'),
|
||||
(2646, 'MMDCXLVI'),
|
||||
(2723, 'MMDCCXXIII'),
|
||||
(2892, 'MMDCCCXCII'),
|
||||
(2975, 'MMCMLXXV'),
|
||||
(3051, 'MMMLI'),
|
||||
(3185, 'MMMCLXXXV'),
|
||||
(3250, 'MMMCCL'),
|
||||
(3313, 'MMMCCCXIII'),
|
||||
(3408, 'MMMCDVIII'),
|
||||
(3501, 'MMMDI'),
|
||||
(3610, 'MMMDCX'),
|
||||
(3743, 'MMMDCCXLIII'),
|
||||
(3844, 'MMMDCCCXLIV'),
|
||||
(3888, 'MMMDCCCLXXXVIII'),
|
||||
(3940, 'MMMCMXL'),
|
||||
(3999, 'MMMCMXCIX'))
|
||||
|
||||
def test_to_roman_known_values(self):
|
||||
"""to_roman should give known result with known input"""
|
||||
for integer, numeral in self.known_values:
|
||||
result = roman6.to_roman(integer)
|
||||
self.assertEqual(numeral, result)
|
||||
|
||||
def test_from_roman_known_values(self):
|
||||
"""from_roman should give known result with known input"""
|
||||
for integer, numeral in self.known_values:
|
||||
result = roman6.from_roman(numeral)
|
||||
self.assertEqual(integer, result)
|
||||
|
||||
class ToRomanBadInput(unittest.TestCase):
|
||||
def test_too_large(self):
|
||||
"""to_roman should fail with large input"""
|
||||
self.assertRaises(roman6.OutOfRangeError, roman6.to_roman, 4000)
|
||||
|
||||
def test_zero(self):
|
||||
"""to_roman should fail with 0 input"""
|
||||
self.assertRaises(roman6.OutOfRangeError, roman6.to_roman, 0)
|
||||
|
||||
def test_negative(self):
|
||||
"""to_roman should fail with negative input"""
|
||||
self.assertRaises(roman6.OutOfRangeError, roman6.to_roman, -1)
|
||||
|
||||
def test_non_integer(self):
|
||||
"""to_roman should fail with non-integer input"""
|
||||
self.assertRaises(roman6.NotIntegerError, roman6.to_roman, 0.5)
|
||||
|
||||
class FromRomanBadInput(unittest.TestCase):
|
||||
def test_too_many_repeated_numerals(self):
|
||||
"""from_roman should fail with too many repeated numerals"""
|
||||
for s in ('MMMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
|
||||
self.assertRaises(roman6.InvalidRomanNumeralError, roman6.from_roman, s)
|
||||
|
||||
def test_repeated_pairs(self):
|
||||
"""from_roman should fail with repeated pairs of numerals"""
|
||||
for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
|
||||
self.assertRaises(roman6.InvalidRomanNumeralError, roman6.from_roman, s)
|
||||
|
||||
def test_malformed_antecedents(self):
|
||||
"""from_roman should fail with malformed antecedents"""
|
||||
for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
|
||||
'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
|
||||
self.assertRaises(roman6.InvalidRomanNumeralError, roman6.from_roman, s)
|
||||
|
||||
class SanityCheck(unittest.TestCase):
|
||||
def testSanity(self):
|
||||
"""from_roman(to_roman(n))==n for all n"""
|
||||
for integer in range(1, 4000):
|
||||
numeral = roman6.to_roman(integer)
|
||||
result = roman6.from_roman(numeral)
|
||||
self.assertEqual(integer, result)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,151 @@
|
||||
"""Unit test for roman1.py
|
||||
|
||||
This program is part of "Dive Into Python 3", a free Python book for
|
||||
experienced programmers. Visit http://diveintopython3.org/ for the
|
||||
latest version.
|
||||
"""
|
||||
|
||||
import roman7
|
||||
import unittest
|
||||
|
||||
class KnownValues(unittest.TestCase):
|
||||
known_values = ( (1, 'I'),
|
||||
(2, 'II'),
|
||||
(3, 'III'),
|
||||
(4, 'IV'),
|
||||
(5, 'V'),
|
||||
(6, 'VI'),
|
||||
(7, 'VII'),
|
||||
(8, 'VIII'),
|
||||
(9, 'IX'),
|
||||
(10, 'X'),
|
||||
(50, 'L'),
|
||||
(100, 'C'),
|
||||
(500, 'D'),
|
||||
(1000, 'M'),
|
||||
(31, 'XXXI'),
|
||||
(148, 'CXLVIII'),
|
||||
(294, 'CCXCIV'),
|
||||
(312, 'CCCXII'),
|
||||
(421, 'CDXXI'),
|
||||
(528, 'DXXVIII'),
|
||||
(621, 'DCXXI'),
|
||||
(782, 'DCCLXXXII'),
|
||||
(870, 'DCCCLXX'),
|
||||
(941, 'CMXLI'),
|
||||
(1043, 'MXLIII'),
|
||||
(1110, 'MCX'),
|
||||
(1226, 'MCCXXVI'),
|
||||
(1301, 'MCCCI'),
|
||||
(1485, 'MCDLXXXV'),
|
||||
(1509, 'MDIX'),
|
||||
(1607, 'MDCVII'),
|
||||
(1754, 'MDCCLIV'),
|
||||
(1832, 'MDCCCXXXII'),
|
||||
(1993, 'MCMXCIII'),
|
||||
(2074, 'MMLXXIV'),
|
||||
(2152, 'MMCLII'),
|
||||
(2212, 'MMCCXII'),
|
||||
(2343, 'MMCCCXLIII'),
|
||||
(2499, 'MMCDXCIX'),
|
||||
(2574, 'MMDLXXIV'),
|
||||
(2646, 'MMDCXLVI'),
|
||||
(2723, 'MMDCCXXIII'),
|
||||
(2892, 'MMDCCCXCII'),
|
||||
(2975, 'MMCMLXXV'),
|
||||
(3051, 'MMMLI'),
|
||||
(3185, 'MMMCLXXXV'),
|
||||
(3250, 'MMMCCL'),
|
||||
(3313, 'MMMCCCXIII'),
|
||||
(3408, 'MMMCDVIII'),
|
||||
(3501, 'MMMDI'),
|
||||
(3610, 'MMMDCX'),
|
||||
(3743, 'MMMDCCXLIII'),
|
||||
(3844, 'MMMDCCCXLIV'),
|
||||
(3888, 'MMMDCCCLXXXVIII'),
|
||||
(3940, 'MMMCMXL'),
|
||||
(3999, 'MMMCMXCIX'))
|
||||
|
||||
def test_to_roman_known_values(self):
|
||||
"""to_roman should give known result with known input"""
|
||||
for integer, numeral in self.known_values:
|
||||
result = roman7.to_roman(integer)
|
||||
self.assertEqual(numeral, result)
|
||||
|
||||
def test_from_roman_known_values(self):
|
||||
"""from_roman should give known result with known input"""
|
||||
for integer, numeral in self.known_values:
|
||||
result = roman7.from_roman(numeral)
|
||||
self.assertEqual(integer, result)
|
||||
|
||||
class ToRomanBadInput(unittest.TestCase):
|
||||
def test_too_large(self):
|
||||
"""to_roman should fail with large input"""
|
||||
self.assertRaises(roman7.OutOfRangeError, roman7.to_roman, 4000)
|
||||
|
||||
def test_zero(self):
|
||||
"""to_roman should fail with 0 input"""
|
||||
self.assertRaises(roman7.OutOfRangeError, roman7.to_roman, 0)
|
||||
|
||||
def test_negative(self):
|
||||
"""to_roman should fail with negative input"""
|
||||
self.assertRaises(roman7.OutOfRangeError, roman7.to_roman, -1)
|
||||
|
||||
def test_non_integer(self):
|
||||
"""to_roman should fail with non-integer input"""
|
||||
self.assertRaises(roman7.NotIntegerError, roman7.to_roman, 0.5)
|
||||
|
||||
class FromRomanBadInput(unittest.TestCase):
|
||||
def test_too_many_repeated_numerals(self):
|
||||
"""from_roman should fail with too many repeated numerals"""
|
||||
for s in ('MMMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
|
||||
self.assertRaises(roman7.InvalidRomanNumeralError, roman7.from_roman, s)
|
||||
|
||||
def test_repeated_pairs(self):
|
||||
"""from_roman should fail with repeated pairs of numerals"""
|
||||
for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
|
||||
self.assertRaises(roman7.InvalidRomanNumeralError, roman7.from_roman, s)
|
||||
|
||||
def test_malformed_antecedents(self):
|
||||
"""from_roman should fail with malformed antecedents"""
|
||||
for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
|
||||
'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
|
||||
self.assertRaises(roman7.InvalidRomanNumeralError, roman7.from_roman, s)
|
||||
|
||||
def test_blank(self):
|
||||
"""from_roman should fail with blank string"""
|
||||
self.assertRaises(roman7.InvalidRomanNumeralError, roman7.from_roman, "")
|
||||
|
||||
class SanityCheck(unittest.TestCase):
|
||||
def testSanity(self):
|
||||
"""from_roman(to_roman(n))==n for all n"""
|
||||
for integer in range(1, 4000):
|
||||
numeral = roman7.to_roman(integer)
|
||||
result = roman7.from_roman(numeral)
|
||||
self.assertEqual(integer, result)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,155 @@
|
||||
"""Unit test for roman1.py
|
||||
|
||||
This program is part of "Dive Into Python 3", a free Python book for
|
||||
experienced programmers. Visit http://diveintopython3.org/ for the
|
||||
latest version.
|
||||
"""
|
||||
|
||||
import roman8
|
||||
import unittest
|
||||
|
||||
class KnownValues(unittest.TestCase):
|
||||
known_values = ( (1, 'I'),
|
||||
(2, 'II'),
|
||||
(3, 'III'),
|
||||
(4, 'IV'),
|
||||
(5, 'V'),
|
||||
(6, 'VI'),
|
||||
(7, 'VII'),
|
||||
(8, 'VIII'),
|
||||
(9, 'IX'),
|
||||
(10, 'X'),
|
||||
(50, 'L'),
|
||||
(100, 'C'),
|
||||
(500, 'D'),
|
||||
(1000, 'M'),
|
||||
(31, 'XXXI'),
|
||||
(148, 'CXLVIII'),
|
||||
(294, 'CCXCIV'),
|
||||
(312, 'CCCXII'),
|
||||
(421, 'CDXXI'),
|
||||
(528, 'DXXVIII'),
|
||||
(621, 'DCXXI'),
|
||||
(782, 'DCCLXXXII'),
|
||||
(870, 'DCCCLXX'),
|
||||
(941, 'CMXLI'),
|
||||
(1043, 'MXLIII'),
|
||||
(1110, 'MCX'),
|
||||
(1226, 'MCCXXVI'),
|
||||
(1301, 'MCCCI'),
|
||||
(1485, 'MCDLXXXV'),
|
||||
(1509, 'MDIX'),
|
||||
(1607, 'MDCVII'),
|
||||
(1754, 'MDCCLIV'),
|
||||
(1832, 'MDCCCXXXII'),
|
||||
(1993, 'MCMXCIII'),
|
||||
(2074, 'MMLXXIV'),
|
||||
(2152, 'MMCLII'),
|
||||
(2212, 'MMCCXII'),
|
||||
(2343, 'MMCCCXLIII'),
|
||||
(2499, 'MMCDXCIX'),
|
||||
(2574, 'MMDLXXIV'),
|
||||
(2646, 'MMDCXLVI'),
|
||||
(2723, 'MMDCCXXIII'),
|
||||
(2892, 'MMDCCCXCII'),
|
||||
(2975, 'MMCMLXXV'),
|
||||
(3051, 'MMMLI'),
|
||||
(3185, 'MMMCLXXXV'),
|
||||
(3250, 'MMMCCL'),
|
||||
(3313, 'MMMCCCXIII'),
|
||||
(3408, 'MMMCDVIII'),
|
||||
(3501, 'MMMDI'),
|
||||
(3610, 'MMMDCX'),
|
||||
(3743, 'MMMDCCXLIII'),
|
||||
(3844, 'MMMDCCCXLIV'),
|
||||
(3888, 'MMMDCCCLXXXVIII'),
|
||||
(3940, 'MMMCMXL'),
|
||||
(3999, 'MMMCMXCIX'))
|
||||
|
||||
def test_to_roman_known_values(self):
|
||||
"""to_roman should give known result with known input"""
|
||||
for integer, numeral in self.known_values:
|
||||
result = roman8.to_roman(integer)
|
||||
self.assertEqual(numeral, result)
|
||||
|
||||
def test_from_roman_known_values(self):
|
||||
"""from_roman should give known result with known input"""
|
||||
for integer, numeral in self.known_values:
|
||||
result = roman8.from_roman(numeral)
|
||||
self.assertEqual(integer, result)
|
||||
|
||||
class ToRomanBadInput(unittest.TestCase):
|
||||
def test_too_large(self):
|
||||
"""to_roman should fail with large input"""
|
||||
self.assertRaises(roman8.OutOfRangeError, roman8.to_roman, 4000)
|
||||
|
||||
def test_zero(self):
|
||||
"""to_roman should fail with 0 input"""
|
||||
self.assertRaises(roman8.OutOfRangeError, roman8.to_roman, 0)
|
||||
|
||||
def test_negative(self):
|
||||
"""to_roman should fail with negative input"""
|
||||
self.assertRaises(roman8.OutOfRangeError, roman8.to_roman, -1)
|
||||
|
||||
def test_non_integer(self):
|
||||
"""to_roman should fail with non-integer input"""
|
||||
self.assertRaises(roman8.NotIntegerError, roman8.to_roman, 0.5)
|
||||
|
||||
class FromRomanBadInput(unittest.TestCase):
|
||||
def test_too_many_repeated_numerals(self):
|
||||
"""from_roman should fail with too many repeated numerals"""
|
||||
for s in ('MMMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
|
||||
self.assertRaises(roman8.InvalidRomanNumeralError, roman8.from_roman, s)
|
||||
|
||||
def test_repeated_pairs(self):
|
||||
"""from_roman should fail with repeated pairs of numerals"""
|
||||
for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
|
||||
self.assertRaises(roman8.InvalidRomanNumeralError, roman8.from_roman, s)
|
||||
|
||||
def test_malformed_antecedents(self):
|
||||
"""from_roman should fail with malformed antecedents"""
|
||||
for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
|
||||
'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
|
||||
self.assertRaises(roman8.InvalidRomanNumeralError, roman8.from_roman, s)
|
||||
|
||||
def test_blank(self):
|
||||
"""from_roman should fail with blank string"""
|
||||
self.assertRaises(roman8.InvalidRomanNumeralError, roman8.from_roman, "")
|
||||
|
||||
def test_non_string(self):
|
||||
"""from_roman should fail with non-string input"""
|
||||
self.assertRaises(roman8.InvalidRomanNumeralError, roman8.from_roman, 1)
|
||||
|
||||
class SanityCheck(unittest.TestCase):
|
||||
def testSanity(self):
|
||||
"""from_roman(to_roman(n))==n for all n"""
|
||||
for integer in range(1, 4000):
|
||||
numeral = roman8.to_roman(integer)
|
||||
result = roman8.from_roman(numeral)
|
||||
self.assertEqual(integer, result)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
Reference in New Issue
Block a user