istr-python 0.0.2__tar.gz → 0.0.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {istr_python-0.0.2/istr_python.egg-info → istr_python-0.0.3}/PKG-INFO +61 -3
- istr_python-0.0.2/PKG-INFO → istr_python-0.0.3/README.md +177 -127
- {istr_python-0.0.2 → istr_python-0.0.3}/istr/istr.py +61 -22
- {istr_python-0.0.2 → istr_python-0.0.3}/istr/sendmoremoney.py +2 -1
- istr_python-0.0.2/README.md → istr_python-0.0.3/istr_python.egg-info/PKG-INFO +185 -119
- {istr_python-0.0.2 → istr_python-0.0.3}/pyproject.toml +1 -2
- {istr_python-0.0.2 → istr_python-0.0.3}/tests/test_istr.py +58 -30
- {istr_python-0.0.2 → istr_python-0.0.3}/istr/__init__.py +0 -0
- {istr_python-0.0.2 → istr_python-0.0.3}/istr/install istr.py +0 -0
- {istr_python-0.0.2 → istr_python-0.0.3}/istr_python.egg-info/SOURCES.txt +0 -0
- {istr_python-0.0.2 → istr_python-0.0.3}/istr_python.egg-info/dependency_links.txt +0 -0
- {istr_python-0.0.2 → istr_python-0.0.3}/istr_python.egg-info/top_level.txt +0 -0
- {istr_python-0.0.2 → istr_python-0.0.3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: istr-python
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.3
|
|
4
4
|
Summary: istr is a module to use strings as if they were integers.
|
|
5
5
|
Author-email: Ruud van der Ham <rt.van.der.ham@gmail.com>
|
|
6
6
|
Requires-Python: >=3.7
|
|
@@ -12,7 +12,26 @@ The istr module has exactly one class: istr.
|
|
|
12
12
|
|
|
13
13
|
With this it is possible to interpret string as if they were integers.
|
|
14
14
|
|
|
15
|
-
This can be very handy for solving puzzles, but also for other purposes.
|
|
15
|
+
This can be very handy for solving puzzles, but also for other purposes. For instance the
|
|
16
|
+
famous send more money puzzle
|
|
17
|
+
```
|
|
18
|
+
S E N D
|
|
19
|
+
M O R E
|
|
20
|
+
--------- +
|
|
21
|
+
M O N E Y
|
|
22
|
+
```
|
|
23
|
+
can be nicely, albeit not very efficient, coded as:
|
|
24
|
+
```
|
|
25
|
+
import itertools
|
|
26
|
+
from istr import istr
|
|
27
|
+
|
|
28
|
+
for s, e, n, d, m, o, r, y in istr(itertools.permutations(range(10), 8)):
|
|
29
|
+
if m and ((s | e | n | d) + (m | o | r | e) == (m | o | n | e | y)):
|
|
30
|
+
print(f" {s|e|n|d}")
|
|
31
|
+
print(f" {m|o|r|e}")
|
|
32
|
+
print("-----")
|
|
33
|
+
print(f"{m|o|n|e|y}")
|
|
34
|
+
```
|
|
16
35
|
|
|
17
36
|
And it is a nice demonstration of extending a class (str) with extra and changed functionality.
|
|
18
37
|
|
|
@@ -91,6 +110,17 @@ abs(four)
|
|
|
91
110
|
-four
|
|
92
111
|
```
|
|
93
112
|
|
|
113
|
+
The bool operator works for integer value of an istr. So
|
|
114
|
+
`bool('0')` ==> `False`
|
|
115
|
+
`bool('1')` ==> `True`
|
|
116
|
+
```
|
|
117
|
+
if istr('0'):
|
|
118
|
+
print("True")
|
|
119
|
+
else:
|
|
120
|
+
print("False")
|
|
121
|
+
```
|
|
122
|
+
this will print `False`
|
|
123
|
+
|
|
94
124
|
For the in operator a istr is treated as an ordinary string, although it is possible to use ints as well:
|
|
95
125
|
```
|
|
96
126
|
"34" in istr(1234)
|
|
@@ -123,5 +153,33 @@ is
|
|
|
123
153
|
|
|
124
154
|
`'0 1 2 3 4 5 6 7 8 9 10 11'`
|
|
125
155
|
|
|
156
|
+
# Using other values for istr than int or str
|
|
157
|
+
Apart from with simple int or str, istr can be initialized with
|
|
158
|
+
|
|
159
|
+
-
|
|
160
|
+
|
|
126
161
|
# Additional methods
|
|
127
|
-
It is possible to test for even/odd
|
|
162
|
+
It is possible to test for even/odd with the
|
|
163
|
+
|
|
164
|
+
`is_even` and `is_odd` method, e.g.
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
print(istr(4).is_even())
|
|
168
|
+
print(istr(5).is_odd())
|
|
169
|
+
```
|
|
170
|
+
This will print `True` twice.
|
|
171
|
+
|
|
172
|
+
The method `istr.reversed()` will return the an istr with the reversed content:
|
|
173
|
+
```
|
|
174
|
+
print(repr(istr(456).reversed()))
|
|
175
|
+
print(repr(istr("0456").reversed()))
|
|
176
|
+
```
|
|
177
|
+
result:
|
|
178
|
+
```
|
|
179
|
+
istr('654')
|
|
180
|
+
istr('6540')
|
|
181
|
+
```
|
|
182
|
+
Note that is impossible to reverse a negative istr.
|
|
183
|
+
|
|
184
|
+
# Subclassing istr
|
|
185
|
+
|
|
@@ -1,127 +1,177 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
1
|
+
# Introduction
|
|
2
|
+
|
|
3
|
+
The istr module has exactly one class: istr.
|
|
4
|
+
|
|
5
|
+
With this it is possible to interpret string as if they were integers.
|
|
6
|
+
|
|
7
|
+
This can be very handy for solving puzzles, but also for other purposes. For instance the
|
|
8
|
+
famous send more money puzzle
|
|
9
|
+
```
|
|
10
|
+
S E N D
|
|
11
|
+
M O R E
|
|
12
|
+
--------- +
|
|
13
|
+
M O N E Y
|
|
14
|
+
```
|
|
15
|
+
can be nicely, albeit not very efficient, coded as:
|
|
16
|
+
```
|
|
17
|
+
import itertools
|
|
18
|
+
from istr import istr
|
|
19
|
+
|
|
20
|
+
for s, e, n, d, m, o, r, y in istr(itertools.permutations(range(10), 8)):
|
|
21
|
+
if m and ((s | e | n | d) + (m | o | r | e) == (m | o | n | e | y)):
|
|
22
|
+
print(f" {s|e|n|d}")
|
|
23
|
+
print(f" {m|o|r|e}")
|
|
24
|
+
print("-----")
|
|
25
|
+
print(f"{m|o|n|e|y}")
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
And it is a nice demonstration of extending a class (str) with extra and changed functionality.
|
|
29
|
+
|
|
30
|
+
# Installation
|
|
31
|
+
Installing istr with pip is easy.
|
|
32
|
+
```
|
|
33
|
+
$ pip install istr-python
|
|
34
|
+
```
|
|
35
|
+
or when you want to upgrade,
|
|
36
|
+
```
|
|
37
|
+
$ pip install istr-python --upgrade
|
|
38
|
+
```
|
|
39
|
+
Alternatively, istr.py can be just copied into you current work directory from GitHub (https://github.com/salabim/istr).
|
|
40
|
+
|
|
41
|
+
No dependencies!
|
|
42
|
+
|
|
43
|
+
# Usage
|
|
44
|
+
Just start with
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
from istr import istr
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Now we can define some istrs:
|
|
51
|
+
```
|
|
52
|
+
four = istr("4")
|
|
53
|
+
five = istr("5")
|
|
54
|
+
```
|
|
55
|
+
Them we can do
|
|
56
|
+
```
|
|
57
|
+
x= four * five
|
|
58
|
+
```
|
|
59
|
+
, after which x is `istr("20")`
|
|
60
|
+
|
|
61
|
+
And now we can do
|
|
62
|
+
```
|
|
63
|
+
print(x == 20)
|
|
64
|
+
print(x == "20")
|
|
65
|
+
```
|
|
66
|
+
resulting in two times `True`. That's because istr instances are treated as int, although they are strings.
|
|
67
|
+
|
|
68
|
+
That means that we can also say
|
|
69
|
+
```
|
|
70
|
+
print(x < 30)
|
|
71
|
+
print(x >= "10")
|
|
72
|
+
```
|
|
73
|
+
again resulting in two times `True`.
|
|
74
|
+
|
|
75
|
+
In contrast to an ordinary string
|
|
76
|
+
```
|
|
77
|
+
print(four + five)
|
|
78
|
+
```
|
|
79
|
+
prints `9`, as istr are treated as ints.
|
|
80
|
+
|
|
81
|
+
So, how can we concatenate istrs? Just use the or operator (|):
|
|
82
|
+
```
|
|
83
|
+
print(four | five)
|
|
84
|
+
```
|
|
85
|
+
will output `45`.
|
|
86
|
+
|
|
87
|
+
And the result is again an istr.
|
|
88
|
+
|
|
89
|
+
That means that
|
|
90
|
+
```
|
|
91
|
+
(four | five) / 3
|
|
92
|
+
```
|
|
93
|
+
is `istr("9")`.
|
|
94
|
+
|
|
95
|
+
In order to multiply a string in the usual sense, you cannot use `3 * four`, as that will be `12`.
|
|
96
|
+
|
|
97
|
+
We use the matrix multiplication operator (@) for this. So `3 @ four` is `444`.
|
|
98
|
+
|
|
99
|
+
Also allowed are
|
|
100
|
+
```
|
|
101
|
+
abs(four)
|
|
102
|
+
-four
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The bool operator works for integer value of an istr. So
|
|
106
|
+
`bool('0')` ==> `False`
|
|
107
|
+
`bool('1')` ==> `True`
|
|
108
|
+
```
|
|
109
|
+
if istr('0'):
|
|
110
|
+
print("True")
|
|
111
|
+
else:
|
|
112
|
+
print("False")
|
|
113
|
+
```
|
|
114
|
+
this will print `False`
|
|
115
|
+
|
|
116
|
+
For the in operator a istr is treated as an ordinary string, although it is possible to use ints as well:
|
|
117
|
+
```
|
|
118
|
+
"34" in istr(1234)
|
|
119
|
+
34 in istr(1234)
|
|
120
|
+
```
|
|
121
|
+
On the left hand side an istr is always treated as a string:
|
|
122
|
+
```
|
|
123
|
+
istr(1234) in "01234566890ABCDEF"
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Note that all calculations are strictly integer calculations. That means that if a float variale is ever produced it will be converted to an int.
|
|
127
|
+
Also divisions are always floor divisions!
|
|
128
|
+
|
|
129
|
+
There's a special case for `istr("")`. This is a proper empty string, but also represents the value of 0.
|
|
130
|
+
That is to allow for istr("").join(i for i in "01234)"
|
|
131
|
+
|
|
132
|
+
Sorting a list of istrs is based on the integer value, not the string. So
|
|
133
|
+
|
|
134
|
+
`' '.join(sorted('1 3 2 4 5 6 11 7 9 8 10 12 0'.split()))`
|
|
135
|
+
|
|
136
|
+
is
|
|
137
|
+
|
|
138
|
+
`'0 1 10 11 2 3 4 5 6 7 8 9'`
|
|
139
|
+
|
|
140
|
+
,whereas
|
|
141
|
+
|
|
142
|
+
`' '.join(sorted(istr('1 3 2 4 5 6 11 7 9 8 10 12 0'.split())))`
|
|
143
|
+
|
|
144
|
+
is
|
|
145
|
+
|
|
146
|
+
`'0 1 2 3 4 5 6 7 8 9 10 11'`
|
|
147
|
+
|
|
148
|
+
# Using other values for istr than int or str
|
|
149
|
+
Apart from with simple int or str, istr can be initialized with
|
|
150
|
+
|
|
151
|
+
-
|
|
152
|
+
|
|
153
|
+
# Additional methods
|
|
154
|
+
It is possible to test for even/odd with the
|
|
155
|
+
|
|
156
|
+
`is_even` and `is_odd` method, e.g.
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
print(istr(4).is_even())
|
|
160
|
+
print(istr(5).is_odd())
|
|
161
|
+
```
|
|
162
|
+
This will print `True` twice.
|
|
163
|
+
|
|
164
|
+
The method `istr.reversed()` will return the an istr with the reversed content:
|
|
165
|
+
```
|
|
166
|
+
print(repr(istr(456).reversed()))
|
|
167
|
+
print(repr(istr("0456").reversed()))
|
|
168
|
+
```
|
|
169
|
+
result:
|
|
170
|
+
```
|
|
171
|
+
istr('654')
|
|
172
|
+
istr('6540')
|
|
173
|
+
```
|
|
174
|
+
Note that is impossible to reverse a negative istr.
|
|
175
|
+
|
|
176
|
+
# Subclassing istr
|
|
177
|
+
|
|
@@ -10,21 +10,37 @@ class istr(str):
|
|
|
10
10
|
Parameters
|
|
11
11
|
----------
|
|
12
12
|
value : any
|
|
13
|
-
value to
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
if str the value will to be interpreted as an int
|
|
14
|
+
istr('8') ==> istr('8')
|
|
15
|
+
if numeric, the value will be interpreted as an int
|
|
16
|
+
istr(8) ==> istr('8')
|
|
17
|
+
if a dict (or subtype of dict), the same type dict will be returned with all values istr'ed
|
|
18
|
+
istr({0: 0, 1: 1, 2: 4}) ==> {0: istr('0'), 1: istr('1'), 2: istr('4')}
|
|
19
|
+
if an iterator, the iterator will be mapped with istr
|
|
20
|
+
istr(i * i for i in range(3)) ==> <map object>
|
|
21
|
+
list(istr(i * i for i in range(3))) ==> [istr('0'), istr('1'), istr('4')]
|
|
22
|
+
if an iterable, the same type will be returned with all elements istr'ed
|
|
23
|
+
istr([0, 1, 4]) ==> [istr('0'), istr('1'), istr('4')]
|
|
24
|
+
istr((0, 1, 4)) ==> (istr('0'), istr('1'), istr('4'))
|
|
25
|
+
istr({0, 1, 4}) ==> {istr('4'), istr('0'), istr('1')} # or similar
|
|
26
|
+
if a range, an istr.range instance will be returned
|
|
27
|
+
istr(range(3)) ==> istr.range(3)
|
|
28
|
+
list(istr(range(3))) ==> [istr('0'), istr('1'), istr('2')]
|
|
29
|
+
len(istr(range(3))) ==> 3
|
|
30
|
+
|
|
31
|
+
it is possible to give more than one parameter, in which case a tuple
|
|
32
|
+
of the istrs of the parameters will be returned, which can be handy
|
|
33
|
+
to multiple assign, e.g.
|
|
34
|
+
a, b, c = istr(5, 6, 7) ==> a=istr("5') , b=istr("6"), c=istr("7")"""
|
|
17
35
|
|
|
18
36
|
_format = ""
|
|
19
37
|
|
|
20
38
|
@classmethod
|
|
21
39
|
def toint(cls, value):
|
|
22
|
-
|
|
23
|
-
return value
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return 0
|
|
27
|
-
return int(value)
|
|
40
|
+
try:
|
|
41
|
+
return int(value)
|
|
42
|
+
except (ValueError, TypeError):
|
|
43
|
+
raise ValueError(f"unable to convert {repr(value)} to int")
|
|
28
44
|
|
|
29
45
|
@classmethod
|
|
30
46
|
def check_format(cls, format):
|
|
@@ -34,25 +50,38 @@ class istr(str):
|
|
|
34
50
|
raise ValueError(f"{repr(format)} is incorrect format")
|
|
35
51
|
return format
|
|
36
52
|
|
|
37
|
-
def __new__(cls, value
|
|
53
|
+
def __new__(cls, *value):
|
|
54
|
+
if len(value) == 0:
|
|
55
|
+
raise TypeError("no parameter given")
|
|
56
|
+
if len(value) == 1:
|
|
57
|
+
value = value[0] # normal case of 1 parameter
|
|
38
58
|
if isinstance(value, range):
|
|
39
59
|
return cls.range(value.start, value.stop, value.step)
|
|
40
|
-
if
|
|
60
|
+
if isinstance(value, dict):
|
|
61
|
+
return type(value)((k, cls(v)) for k, v in value.items())
|
|
62
|
+
if not isinstance(value, (str, type)) and hasattr(value, "__iter__"):
|
|
41
63
|
if hasattr(value, "__next__") or type(value) == range:
|
|
42
64
|
return map(partial(cls), value)
|
|
43
65
|
return type(value)(map(partial(cls), value))
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
66
|
+
if value == "":
|
|
67
|
+
asstr = ""
|
|
68
|
+
asint = 0
|
|
47
69
|
else:
|
|
48
|
-
|
|
70
|
+
asint = cls.toint(value)
|
|
71
|
+
if cls._format == "":
|
|
72
|
+
if isinstance(value, str):
|
|
73
|
+
asstr = value
|
|
74
|
+
else:
|
|
75
|
+
asstr = str(asint)
|
|
76
|
+
else:
|
|
77
|
+
asstr = f"{asint:{cls._format}}"
|
|
49
78
|
|
|
50
|
-
|
|
51
|
-
self.asint =
|
|
52
|
-
|
|
79
|
+
self = super().__new__(cls, asstr)
|
|
80
|
+
self.asint = asint
|
|
81
|
+
return self
|
|
53
82
|
|
|
54
83
|
def __hash__(self):
|
|
55
|
-
return hash((self.__class__, self
|
|
84
|
+
return hash((self.__class__, str(self)))
|
|
56
85
|
|
|
57
86
|
def __eq__(self, other):
|
|
58
87
|
if isinstance(other, self.__class__):
|
|
@@ -85,6 +114,9 @@ class istr(str):
|
|
|
85
114
|
def __gt__(self, other):
|
|
86
115
|
return self.asint > self.toint(other)
|
|
87
116
|
|
|
117
|
+
def __bool__(self):
|
|
118
|
+
return bool(self.asint)
|
|
119
|
+
|
|
88
120
|
def __add__(self, other):
|
|
89
121
|
return self.__class__(self.asint + self.toint(other))
|
|
90
122
|
|
|
@@ -179,6 +211,12 @@ class istr(str):
|
|
|
179
211
|
s = super().join(iterable)
|
|
180
212
|
return self.__class__(s)
|
|
181
213
|
|
|
214
|
+
def reversed(self):
|
|
215
|
+
return self[::-1]
|
|
216
|
+
|
|
217
|
+
def __getitem__(self, key):
|
|
218
|
+
return self.__class__(super().__getitem__(key))
|
|
219
|
+
|
|
182
220
|
@classmethod
|
|
183
221
|
def enumerate(cls, iterable, start=0):
|
|
184
222
|
for i, value in enumerate(iterable, start):
|
|
@@ -344,8 +382,9 @@ class istr(str):
|
|
|
344
382
|
|
|
345
383
|
|
|
346
384
|
def main():
|
|
347
|
-
|
|
385
|
+
zero=istr("0")
|
|
386
|
+
print(bool(zero))
|
|
387
|
+
|
|
348
388
|
|
|
349
389
|
if __name__ == "__main__":
|
|
350
390
|
main()
|
|
351
|
-
|
|
@@ -1,119 +1,185 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
(
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: istr-python
|
|
3
|
+
Version: 0.0.3
|
|
4
|
+
Summary: istr is a module to use strings as if they were integers.
|
|
5
|
+
Author-email: Ruud van der Ham <rt.van.der.ham@gmail.com>
|
|
6
|
+
Requires-Python: >=3.7
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
|
|
9
|
+
# Introduction
|
|
10
|
+
|
|
11
|
+
The istr module has exactly one class: istr.
|
|
12
|
+
|
|
13
|
+
With this it is possible to interpret string as if they were integers.
|
|
14
|
+
|
|
15
|
+
This can be very handy for solving puzzles, but also for other purposes. For instance the
|
|
16
|
+
famous send more money puzzle
|
|
17
|
+
```
|
|
18
|
+
S E N D
|
|
19
|
+
M O R E
|
|
20
|
+
--------- +
|
|
21
|
+
M O N E Y
|
|
22
|
+
```
|
|
23
|
+
can be nicely, albeit not very efficient, coded as:
|
|
24
|
+
```
|
|
25
|
+
import itertools
|
|
26
|
+
from istr import istr
|
|
27
|
+
|
|
28
|
+
for s, e, n, d, m, o, r, y in istr(itertools.permutations(range(10), 8)):
|
|
29
|
+
if m and ((s | e | n | d) + (m | o | r | e) == (m | o | n | e | y)):
|
|
30
|
+
print(f" {s|e|n|d}")
|
|
31
|
+
print(f" {m|o|r|e}")
|
|
32
|
+
print("-----")
|
|
33
|
+
print(f"{m|o|n|e|y}")
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
And it is a nice demonstration of extending a class (str) with extra and changed functionality.
|
|
37
|
+
|
|
38
|
+
# Installation
|
|
39
|
+
Installing istr with pip is easy.
|
|
40
|
+
```
|
|
41
|
+
$ pip install istr-python
|
|
42
|
+
```
|
|
43
|
+
or when you want to upgrade,
|
|
44
|
+
```
|
|
45
|
+
$ pip install istr-python --upgrade
|
|
46
|
+
```
|
|
47
|
+
Alternatively, istr.py can be just copied into you current work directory from GitHub (https://github.com/salabim/istr).
|
|
48
|
+
|
|
49
|
+
No dependencies!
|
|
50
|
+
|
|
51
|
+
# Usage
|
|
52
|
+
Just start with
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
from istr import istr
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Now we can define some istrs:
|
|
59
|
+
```
|
|
60
|
+
four = istr("4")
|
|
61
|
+
five = istr("5")
|
|
62
|
+
```
|
|
63
|
+
Them we can do
|
|
64
|
+
```
|
|
65
|
+
x= four * five
|
|
66
|
+
```
|
|
67
|
+
, after which x is `istr("20")`
|
|
68
|
+
|
|
69
|
+
And now we can do
|
|
70
|
+
```
|
|
71
|
+
print(x == 20)
|
|
72
|
+
print(x == "20")
|
|
73
|
+
```
|
|
74
|
+
resulting in two times `True`. That's because istr instances are treated as int, although they are strings.
|
|
75
|
+
|
|
76
|
+
That means that we can also say
|
|
77
|
+
```
|
|
78
|
+
print(x < 30)
|
|
79
|
+
print(x >= "10")
|
|
80
|
+
```
|
|
81
|
+
again resulting in two times `True`.
|
|
82
|
+
|
|
83
|
+
In contrast to an ordinary string
|
|
84
|
+
```
|
|
85
|
+
print(four + five)
|
|
86
|
+
```
|
|
87
|
+
prints `9`, as istr are treated as ints.
|
|
88
|
+
|
|
89
|
+
So, how can we concatenate istrs? Just use the or operator (|):
|
|
90
|
+
```
|
|
91
|
+
print(four | five)
|
|
92
|
+
```
|
|
93
|
+
will output `45`.
|
|
94
|
+
|
|
95
|
+
And the result is again an istr.
|
|
96
|
+
|
|
97
|
+
That means that
|
|
98
|
+
```
|
|
99
|
+
(four | five) / 3
|
|
100
|
+
```
|
|
101
|
+
is `istr("9")`.
|
|
102
|
+
|
|
103
|
+
In order to multiply a string in the usual sense, you cannot use `3 * four`, as that will be `12`.
|
|
104
|
+
|
|
105
|
+
We use the matrix multiplication operator (@) for this. So `3 @ four` is `444`.
|
|
106
|
+
|
|
107
|
+
Also allowed are
|
|
108
|
+
```
|
|
109
|
+
abs(four)
|
|
110
|
+
-four
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The bool operator works for integer value of an istr. So
|
|
114
|
+
`bool('0')` ==> `False`
|
|
115
|
+
`bool('1')` ==> `True`
|
|
116
|
+
```
|
|
117
|
+
if istr('0'):
|
|
118
|
+
print("True")
|
|
119
|
+
else:
|
|
120
|
+
print("False")
|
|
121
|
+
```
|
|
122
|
+
this will print `False`
|
|
123
|
+
|
|
124
|
+
For the in operator a istr is treated as an ordinary string, although it is possible to use ints as well:
|
|
125
|
+
```
|
|
126
|
+
"34" in istr(1234)
|
|
127
|
+
34 in istr(1234)
|
|
128
|
+
```
|
|
129
|
+
On the left hand side an istr is always treated as a string:
|
|
130
|
+
```
|
|
131
|
+
istr(1234) in "01234566890ABCDEF"
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Note that all calculations are strictly integer calculations. That means that if a float variale is ever produced it will be converted to an int.
|
|
135
|
+
Also divisions are always floor divisions!
|
|
136
|
+
|
|
137
|
+
There's a special case for `istr("")`. This is a proper empty string, but also represents the value of 0.
|
|
138
|
+
That is to allow for istr("").join(i for i in "01234)"
|
|
139
|
+
|
|
140
|
+
Sorting a list of istrs is based on the integer value, not the string. So
|
|
141
|
+
|
|
142
|
+
`' '.join(sorted('1 3 2 4 5 6 11 7 9 8 10 12 0'.split()))`
|
|
143
|
+
|
|
144
|
+
is
|
|
145
|
+
|
|
146
|
+
`'0 1 10 11 2 3 4 5 6 7 8 9'`
|
|
147
|
+
|
|
148
|
+
,whereas
|
|
149
|
+
|
|
150
|
+
`' '.join(sorted(istr('1 3 2 4 5 6 11 7 9 8 10 12 0'.split())))`
|
|
151
|
+
|
|
152
|
+
is
|
|
153
|
+
|
|
154
|
+
`'0 1 2 3 4 5 6 7 8 9 10 11'`
|
|
155
|
+
|
|
156
|
+
# Using other values for istr than int or str
|
|
157
|
+
Apart from with simple int or str, istr can be initialized with
|
|
158
|
+
|
|
159
|
+
-
|
|
160
|
+
|
|
161
|
+
# Additional methods
|
|
162
|
+
It is possible to test for even/odd with the
|
|
163
|
+
|
|
164
|
+
`is_even` and `is_odd` method, e.g.
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
print(istr(4).is_even())
|
|
168
|
+
print(istr(5).is_odd())
|
|
169
|
+
```
|
|
170
|
+
This will print `True` twice.
|
|
171
|
+
|
|
172
|
+
The method `istr.reversed()` will return the an istr with the reversed content:
|
|
173
|
+
```
|
|
174
|
+
print(repr(istr(456).reversed()))
|
|
175
|
+
print(repr(istr("0456").reversed()))
|
|
176
|
+
```
|
|
177
|
+
result:
|
|
178
|
+
```
|
|
179
|
+
istr('654')
|
|
180
|
+
istr('6540')
|
|
181
|
+
```
|
|
182
|
+
Note that is impossible to reverse a negative istr.
|
|
183
|
+
|
|
184
|
+
# Subclassing istr
|
|
185
|
+
|
|
@@ -8,8 +8,7 @@ authors = [
|
|
|
8
8
|
{name = "Ruud van der Ham", email = "rt.van.der.ham@gmail.com"}
|
|
9
9
|
]
|
|
10
10
|
description = "istr is a module to use strings as if they were integers."
|
|
11
|
-
|
|
12
|
-
version = "0.0.2"
|
|
11
|
+
version = "0.0.3"
|
|
13
12
|
readme = "README.md"
|
|
14
13
|
requires-python = ">=3.7"
|
|
15
14
|
dependencies = [
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
from __future__ import print_function
|
|
2
|
-
from __future__ import division
|
|
3
|
-
from istr import istr
|
|
4
1
|
import math
|
|
5
2
|
|
|
3
|
+
if __name__ == "__main__": # to make the tests run without the pytest cli
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
sys.path = ["../istr"] + sys.path
|
|
7
|
+
|
|
6
8
|
import pytest
|
|
7
9
|
|
|
10
|
+
from istr import istr
|
|
11
|
+
|
|
12
|
+
istr.equals = lambda self, other: type(self) == type(other) and (str(self) == str(other))
|
|
13
|
+
# this method tests whether self and other are exactly the same
|
|
14
|
+
|
|
8
15
|
for i, name in enumerate("minus_one zero one two three four five six seven eight nine ten eleven twelve thirteen".split(), -1):
|
|
9
16
|
globals()[name] = istr(i)
|
|
10
17
|
one_to_twelve = istr.range(1, thirteen)
|
|
@@ -161,8 +168,8 @@ def test_misc():
|
|
|
161
168
|
assert istr(istr(6)) == "6"
|
|
162
169
|
assert istr(" 12 ") == " 12 "
|
|
163
170
|
with istr.format("03"):
|
|
164
|
-
assert istr("
|
|
165
|
-
assert istr("")==""
|
|
171
|
+
assert istr(" 12 ") == "012"
|
|
172
|
+
assert istr("") == ""
|
|
166
173
|
|
|
167
174
|
|
|
168
175
|
def test_divmod():
|
|
@@ -193,7 +200,7 @@ def test_lazy():
|
|
|
193
200
|
|
|
194
201
|
|
|
195
202
|
def test_str_repr():
|
|
196
|
-
assert
|
|
203
|
+
assert one.equals(istr("1"))
|
|
197
204
|
assert str(one) == "1"
|
|
198
205
|
assert f"{one}" == "1"
|
|
199
206
|
assert repr(one_to_twelve) == "istr.range(1, 13)"
|
|
@@ -306,11 +313,8 @@ def test_join():
|
|
|
306
313
|
|
|
307
314
|
|
|
308
315
|
def test_matmul():
|
|
309
|
-
assert five @ 3
|
|
310
|
-
assert
|
|
311
|
-
|
|
312
|
-
assert 3 @ five == "555"
|
|
313
|
-
assert 3 @ five == 555
|
|
316
|
+
assert (five @ 3).equals(istr("555"))
|
|
317
|
+
assert (3 @ five).equals(istr("555"))
|
|
314
318
|
|
|
315
319
|
with pytest.raises(TypeError):
|
|
316
320
|
three @ five
|
|
@@ -319,44 +323,68 @@ def test_matmul():
|
|
|
319
323
|
with pytest.raises(TypeError):
|
|
320
324
|
"3" @ five
|
|
321
325
|
|
|
322
|
-
|
|
323
326
|
def test_str():
|
|
324
327
|
assert repr(str(five)) == "'5'"
|
|
325
328
|
|
|
326
329
|
|
|
327
330
|
def test_trunc_and_friends():
|
|
328
|
-
assert
|
|
329
|
-
assert
|
|
330
|
-
assert
|
|
331
|
-
assert
|
|
331
|
+
assert math.trunc(one).equals(istr("1"))
|
|
332
|
+
assert math.ceil(one).equals(istr("1"))
|
|
333
|
+
assert math.floor(one).equals(istr("1"))
|
|
334
|
+
assert round(one).equals(istr("1"))
|
|
332
335
|
|
|
333
336
|
|
|
334
337
|
def test_data_structures():
|
|
335
|
-
assert istr(list(range(1, 4))) == [1, 2, 3]
|
|
336
|
-
assert istr(
|
|
337
|
-
|
|
338
|
-
assert istr(tuple(range(1, 4))) == (1, 2, 3)
|
|
339
|
-
assert istr(tuple(range(1, 4))) == ("1", "2", "3")
|
|
338
|
+
assert repr(istr(list(range(1, 4)))) == "[istr('1'), istr('2'), istr('3')]"
|
|
339
|
+
assert repr(istr(tuple(range(1, 4)))) == "(istr('1'), istr('2'), istr('3'))"
|
|
340
340
|
assert istr(set(range(1, 4))) == {istr(1), istr(2), istr(3)}
|
|
341
341
|
|
|
342
|
-
assert list(istr(range(1, 4))) == [1, 2, 3]
|
|
343
|
-
|
|
342
|
+
assert repr(list(istr(range(1, 4)))) == "[istr('1'), istr('2'), istr('3')]"
|
|
343
|
+
|
|
344
|
+
assert repr(list(istr.enumerate("abc"))) == "[(istr('0'), 'a'), (istr('1'), 'b'), (istr('2'), 'c')]"
|
|
345
|
+
assert repr(list(istr.enumerate("abc", 1))) == "[(istr('1'), 'a'), (istr('2'), 'b'), (istr('3'), 'c')]"
|
|
346
|
+
|
|
347
|
+
assert repr(istr(dict(zero=0, one=1, two=4))) == "{'zero': istr('0'), 'one': istr('1'), 'two': istr('4')}"
|
|
344
348
|
|
|
345
|
-
assert list(istr(range(1, 4))) == [1, 2, 3]
|
|
346
|
-
assert list(istr(range(1, 4))) == ["1", "2", "3"]
|
|
347
349
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
+
def test_indexing():
|
|
351
|
+
a = istr(12345)
|
|
352
|
+
assert a[0].equals(istr(1))
|
|
353
|
+
assert a[:2].equals(istr(12))
|
|
354
|
+
assert a[::-1].equals(istr(54321))
|
|
355
|
+
assert a[-2:].equals(istr(45))
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def test_reverse():
|
|
359
|
+
a = istr(12345)
|
|
360
|
+
assert a.reversed(), same(istr(54321))
|
|
350
361
|
|
|
351
362
|
|
|
352
363
|
def test_edge_cases():
|
|
353
364
|
with pytest.raises(ValueError):
|
|
354
365
|
istr("ab")
|
|
355
|
-
with pytest.raises(
|
|
366
|
+
with pytest.raises(ValueError):
|
|
356
367
|
istr(istr)
|
|
357
|
-
assert
|
|
368
|
+
assert istr(istr(one)).equals(istr("1"))
|
|
369
|
+
with pytest.raises(TypeError):
|
|
370
|
+
istr()
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
def test_unpacking():
|
|
374
|
+
a = istr("123")
|
|
375
|
+
x, y, z = istr(*a)
|
|
376
|
+
assert x.equals(istr(1))
|
|
377
|
+
assert y.equals(istr(2))
|
|
378
|
+
assert z.equals(istr(3))
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def test_subclassing():
|
|
382
|
+
class jstr(istr):
|
|
383
|
+
...
|
|
384
|
+
|
|
385
|
+
assert jstr(5).equals(jstr(5))
|
|
386
|
+
assert repr(jstr(*range(3))) == "(jstr('0'), jstr('1'), jstr('2'))"
|
|
358
387
|
|
|
359
388
|
|
|
360
389
|
if __name__ == "__main__":
|
|
361
390
|
pytest.main(["-vv", "-s", "-x", __file__])
|
|
362
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|