Skip to content

Commit 34470ae

Browse files
got the final step from DiP done -- but a bit more to do
1 parent 9373a75 commit 34470ae

File tree

6 files changed

+1099
-149
lines changed

6 files changed

+1099
-149
lines changed

source/examples/test_driven_development/roman13.py

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,21 +43,73 @@ def to_roman(n):
4343

4444
def is_valid_roman_numeral(s):
4545
"""
46-
check if the input is a valid roman numeral
47-
48-
returns True if it is, False other wise
46+
parse a Roman numeral as a human would: left to right,
47+
looking for valid characters and removing them to determine
48+
if this is, indeed, a valid Roman numeral
4949
"""
50-
# does it use only valid characters?
50+
# first check if uses only valid characters
5151
for c in s:
5252
if c not in "MDCLXVI":
5353
return False
5454

55-
# are any chars repeated too much?
56-
for c in ('MMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
57-
if c in s:
58-
return False
59-
60-
return True
55+
print("starting to parse")
56+
print("the thousands")
57+
print(f"{s = }")
58+
# first look for the thousands -- up to three Ms
59+
for _ in range(3):
60+
if s[:1] == "M":
61+
s = s[1:]
62+
# then look for the hundreds:
63+
print("the hundreds")
64+
print(f"{s = }")
65+
# there can be ony one of CM, CD, or D:
66+
if s[:2] == "CM": # 900
67+
s = s[2:]
68+
elif s[:2] == "CD": # 400
69+
s = s[2:]
70+
elif s[:1] == "D": # 500
71+
s = s[1:]
72+
# there can be from 1 to 3 Cs
73+
for _ in range(3):
74+
if s[:1] == "C":
75+
s = s[1:]
76+
# now the tens
77+
print("the tens")
78+
print(f"{s = }")
79+
# There can be one of either XC, XL or L
80+
if s[:2] == "XC": # 90
81+
s = s[2:]
82+
elif s[:2] == "XL": # 40
83+
s = s[2:]
84+
elif s[:1] == "L": # 50
85+
s = s[1:]
86+
# there can be up to three Xs
87+
for _ in range(3):
88+
if s[:1] == "X":
89+
s = s[1:]
90+
# and the ones
91+
print("the ones")
92+
print(f"{s = }")
93+
# There can be one of IX, IV or V
94+
if s[:2] == "IX": # 9
95+
s = s[2:]
96+
elif s[:2] == "IV": # 4
97+
s = s[2:]
98+
elif s[:1] == "V": # 5
99+
s = s[1:]
100+
print("looking for the Is")
101+
print(f"{s = }")
102+
# There can be up to three Is
103+
for _ in range(3):
104+
if s[:1] == "I": # 1
105+
s = s[1:]
106+
# if there is anything left, it's not a valid Roman numeral
107+
print("done")
108+
print(f"{s = }")
109+
if s:
110+
return False
111+
else:
112+
return True
61113

62114

63115
def from_roman(s):
@@ -216,13 +268,15 @@ def test_too_many_repeated_numerals():
216268
'''from_roman should fail with too many repeated numerals'''
217269
for s in ('MMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
218270
with pytest.raises(ValueError):
271+
print(f"trying: {s}")
219272
from_roman(s)
220273

221274

222275
def test_repeated_pairs():
223276
'''from_roman should fail with repeated pairs of numerals'''
224277
for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
225278
with pytest.raises(ValueError):
279+
print(f"trying: {s}")
226280
from_roman(s)
227281

228282

@@ -231,6 +285,7 @@ def test_malformed_antecedents():
231285
for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
232286
'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
233287
with pytest.raises(ValueError):
288+
print(f"trying: {s}")
234289
from_roman(s)
235290

236291

source/examples/test_driven_development/roman14.py

Lines changed: 66 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -43,27 +43,74 @@ def to_roman(n):
4343

4444
def is_valid_roman_numeral(s):
4545
"""
46-
check if the input is a valid roman numeral
47-
48-
returns True if it is, False other wise
46+
parse a Roman numeral as a human would: left to right,
47+
looking for valid characters and removing them to determine
48+
if this is, indeed, a valid Roman numeral
4949
"""
50-
# does it use only valid characters?
50+
# first check if uses only valid characters
5151
for c in s:
5252
if c not in "MDCLXVI":
5353
return False
5454

55-
# are any chars repeated too much?
56-
for c in ('MMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
57-
if c in s:
58-
return False
59-
60-
# are any of the subtractive patterns repeated?
61-
for pattern in ["IV", "IX", "XC", "CM", "CD"]:
62-
if s.count(pattern) > 1:
63-
return False
64-
65-
66-
return True
55+
print("starting to parse")
56+
print("the thousands")
57+
print(f"{s = }")
58+
# first look for the thousands -- up to three Ms
59+
for _ in range(3):
60+
if s[:1] == "M":
61+
s = s[1:]
62+
# then look for the hundreds:
63+
print("the hundreds")
64+
print(f"{s = }")
65+
# there can be only one of CM, CD, or D:
66+
if s[:2] == "CM": # 900
67+
s = s[2:]
68+
elif s[:2] == "CD": # 400
69+
s = s[2:]
70+
else:
71+
if s[:1] == "D": # 500
72+
s = s[1:]
73+
# there can be from 1 to 3 Cs
74+
for _ in range(3):
75+
if s[:1] == "C":
76+
s = s[1:]
77+
# now the tens
78+
print("the tens")
79+
print(f"{s = }")
80+
# There can be one of either XC, XL or L
81+
if s[:2] == "XC": # 90
82+
s = s[2:]
83+
elif s[:2] == "XL": # 40
84+
s = s[2:]
85+
elif s[:1] == "L": # 50
86+
s = s[1:]
87+
# there can be up to three Xs
88+
for _ in range(3):
89+
if s[:1] == "X":
90+
s = s[1:]
91+
# and the ones
92+
print("the ones")
93+
print(f"{s = }")
94+
# There can be one of IX, IV or V
95+
if s[:2] == "IX": # 9
96+
s = s[2:]
97+
elif s[:2] == "IV": # 4
98+
s = s[2:]
99+
elif s[:1] == "V": # 5
100+
s = s[1:]
101+
print("looking for the Is")
102+
print(f"{s = }")
103+
# There can be up to three Is
104+
for _ in range(3):
105+
if s[:1] == "I": # 1
106+
s = s[1:]
107+
# if there is anything left, it's not a valid Roman numeral
108+
print("done")
109+
print(f"{s = }")
110+
if s:
111+
return False
112+
else:
113+
return True
67114

68115

69116
def from_roman(s):
@@ -222,13 +269,15 @@ def test_too_many_repeated_numerals():
222269
'''from_roman should fail with too many repeated numerals'''
223270
for s in ('MMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
224271
with pytest.raises(ValueError):
272+
print(f"trying: {s}")
225273
from_roman(s)
226274

227275

228276
def test_repeated_pairs():
229277
'''from_roman should fail with repeated pairs of numerals'''
230278
for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
231279
with pytest.raises(ValueError):
280+
print(f"trying: {s}")
232281
from_roman(s)
233282

234283

@@ -237,6 +286,7 @@ def test_malformed_antecedents():
237286
for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
238287
'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
239288
with pytest.raises(ValueError):
289+
print(f"trying: {s}")
240290
from_roman(s)
241291

242292

source/examples/test_driven_development/roman15.py

Lines changed: 44 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -43,100 +43,75 @@ def to_roman(n):
4343

4444
def is_valid_roman_numeral(s):
4545
"""
46-
check if the input is a valid roman numeral
47-
48-
returns True if it is, False other wise
46+
parse a Roman numeral as a human would: left to right,
47+
looking for valid characters and removing them to determine
48+
if this is, indeed, a valid Roman numeral
4949
"""
50-
# does it use only valid characters?
50+
# first check if uses only valid characters
5151
for c in s:
5252
if c not in "MDCLXVI":
5353
return False
5454

55-
# are any chars repeated too much?
56-
for c in ('MMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
57-
if c in s:
58-
return False
59-
60-
# are any of the subtractive patterns repeated?
61-
for pattern in ["IV", "IX", "XC", "CM", "CD"]:
62-
if s.count(pattern) > 1:
63-
return False
64-
65-
return True
66-
67-
def is_valid_roman_numeral(s):
68-
"""
69-
parse a Roman numeral as a human would: left to right
70-
to determine if this is, indeed a roman numeral
71-
"""
72-
print("starting")
73-
value = 0
55+
print("starting to parse")
7456
print("the thousands")
75-
print(f"{s = }, {value = }")
76-
# first look for the thousands -- up to three
57+
print(f"{s = }")
58+
# first look for the thousands -- up to three Ms
7759
for _ in range(3):
7860
if s[:1] == "M":
79-
value += 1000
8061
s = s[1:]
81-
# then look for the hundreds
62+
# then look for the hundreds:
8263
print("the hundreds")
83-
print(f"{s = }, {value = }")
84-
if s[:2] == "CM":
85-
value += 900
64+
print(f"{s = }")
65+
# there can be only one of CM, CD, or D:
66+
if s[:2] == "CM": # 900
8667
s = s[2:]
87-
elif s[:2] == "CD":
88-
value += 400
68+
elif s[:2] == "CD": # 400
8969
s = s[2:]
90-
elif s[:1] == "D":
91-
value += 500
92-
s = s[1:]
93-
for _ in range(3):
94-
if s[:1] == "C":
95-
value += 100
70+
else:
71+
if s[:1] == "D": # 500
9672
s = s[1:]
73+
# there can be from 1 to 3 Cs
74+
for _ in range(3):
75+
if s[:1] == "C":
76+
s = s[1:]
9777
# now the tens
9878
print("the tens")
99-
print(f"{s = }, {value = }")
100-
if s[:2] == "XC":
101-
value += 90
79+
print(f"{s = }")
80+
# There can be one of either XC, XL or L
81+
if s[:2] == "XC": # 90
10282
s = s[2:]
103-
elif s[:2] == "XL":
104-
value += 40
83+
elif s[:2] == "XL": # 40
10584
s = s[2:]
106-
elif s[:1] == "L":
107-
value += 50
108-
s = s[1:]
109-
for _ in range(3):
110-
if s[:1] == "X":
111-
value += 10
85+
else:
86+
if s[:1] == "L": # 50
11287
s = s[1:]
88+
# there can be up to three Xs
89+
for _ in range(3):
90+
if s[:1] == "X":
91+
s = s[1:]
11392
# and the ones
11493
print("the ones")
115-
print(f"{s = }, {value = }")
116-
if s[:2] == "IX":
117-
value += 9
94+
print(f"{s = }")
95+
# There can be one of IX, IV or V
96+
if s[:2] == "IX": # 9
11897
s = s[2:]
119-
elif s[:2] == "IV":
120-
value += 4
98+
elif s[:2] == "IV": # 4
12199
s = s[2:]
122-
elif s[:1] == "V":
123-
value += 5
100+
elif s[:1] == "V": # 5
124101
s = s[1:]
125-
# else:
126102
print("looking for the Is")
127-
print(f"{s = }, {value = }")
103+
print(f"{s = }")
104+
# There can be up to three Is
128105
for _ in range(3):
129-
if s[:1] == "I":
130-
value += 1
106+
if s[:1] == "I": # 1
131107
s = s[1:]
132-
# if there is anything left, it's not a valid
133-
# Roman numeral
108+
# if there is anything left, it's not a valid Roman numeral
134109
print("done")
135-
print(f"{s = }, {value = }")
136-
if s == "":
137-
return True
138-
else:
110+
print(f"{s = }")
111+
if s:
139112
return False
113+
else:
114+
return True
140115

141116

142117
def from_roman(s):
@@ -295,13 +270,15 @@ def test_too_many_repeated_numerals():
295270
'''from_roman should fail with too many repeated numerals'''
296271
for s in ('MMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'):
297272
with pytest.raises(ValueError):
273+
print(f"trying: {s}")
298274
from_roman(s)
299275

300276

301277
def test_repeated_pairs():
302278
'''from_roman should fail with repeated pairs of numerals'''
303279
for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'):
304280
with pytest.raises(ValueError):
281+
print(f"trying: {s}")
305282
from_roman(s)
306283

307284

@@ -310,6 +287,7 @@ def test_malformed_antecedents():
310287
for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV',
311288
'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'):
312289
with pytest.raises(ValueError):
290+
print(f"trying: {s}")
313291
from_roman(s)
314292

315293

0 commit comments

Comments
 (0)