istr-python 0.0.7__tar.gz → 0.1.0__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.
@@ -0,0 +1,421 @@
1
+ Metadata-Version: 2.1
2
+ Name: istr-python
3
+ Version: 0.1.0
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
+ Project-URL: Homepage, https://github.com/salabim/istr
7
+ Project-URL: Repository, https://github.com/salabim/istr
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3 :: Only
11
+ Requires-Python: >=3.7
12
+ Description-Content-Type: text/markdown
13
+
14
+ <img src="https://www.salabim.org/istr.png" width=500>
15
+
16
+ # Introduction
17
+
18
+ The istr module has exactly one class: istr.
19
+
20
+ With this it is possible to interpret strings as if they were integers.
21
+
22
+ This can be very handy for solving puzzles, but also for other purposes. For instance the
23
+ famous send more money puzzle
24
+ ```
25
+ S E N D
26
+ M O R E
27
+ --------- +
28
+ M O N E Y
29
+ ```
30
+ can be nicely, albeit not very efficient, coded as:
31
+ ```
32
+ import itertools
33
+ from istr import istr
34
+
35
+ for s, e, n, d, m, o, r, y in istr(itertools.permutations(range(10), 8)):
36
+ if m and ((s|e|n|d) + (m|o|r|e) == (m|o|n|e|y)):
37
+ print(f" {s|e|n|d}")
38
+ print(f" {m|o|r|e}")
39
+ print("-----")
40
+ print(f"{m|o|n|e|y}")
41
+ ```
42
+
43
+ And it is a nice demonstration of extending a class (str) with extra and changed functionality.
44
+
45
+ # Installation
46
+ Installing istr with pip is easy.
47
+ ```
48
+ $ pip install istr-python
49
+ ```
50
+ or when you want to upgrade,
51
+ ```
52
+ $ pip install istr-python --upgrade
53
+ ```
54
+ Alternatively, istr.py can be just copied into you current work directory from GitHub (https://github.com/salabim/istr).
55
+
56
+ No dependencies!
57
+
58
+ # Usage
59
+ Just start with
60
+
61
+ ```
62
+ from istr import istr
63
+ ```
64
+
65
+ Now we can define some istrs:
66
+ ```
67
+ four = istr("4")
68
+ five = istr("5")
69
+ ```
70
+ Then we can do
71
+ ```
72
+ x= four * five
73
+ ```
74
+ , after which x is `istr("20")`
75
+
76
+ And now we can do
77
+ ```
78
+ print(x == 20)
79
+ print(x == "20")
80
+ ```
81
+ resulting in two times `True`. That's because istrs instances are treated as int, although they are strings.
82
+
83
+ That means that we can also say
84
+ ```
85
+ print(x < 30)
86
+ print(x >= "10")
87
+ ```
88
+ again resulting in two times `True`.
89
+
90
+ In contrast to an ordinary string
91
+ ```
92
+ print(four + five)
93
+ ```
94
+ prints `9`, as istr are treated as ints.
95
+
96
+ Please note that `four` and `five` could have also be initialized with
97
+ ```
98
+ four = istr(4)
99
+ five = istr(5)
100
+ ```
101
+ or even
102
+ ```
103
+ four, five = istr(4, 5)
104
+ ```
105
+
106
+ But how can we concatenate istrs? Just use the or operator (|):
107
+ ```
108
+ print(four | five)
109
+ ```
110
+ will output `45`.
111
+
112
+ And the result is again an istr.
113
+
114
+ That means that
115
+ ```
116
+ (four | five) / 3
117
+ ```
118
+ is `istr("9")`.
119
+
120
+ In order to repeat a string in the usual sense, you cannot use `3 * four`, as that woud be `12`.
121
+
122
+ We use the matrix multiplication operator (@) for this. So `3 @ four` is `444`. As is `four @ 3`.
123
+
124
+ Also allowed are
125
+ ```
126
+ abs(four)
127
+ -four
128
+ ```
129
+
130
+ The bool operator works on the integer value of an istr. So
131
+ `bool("0")` ==> `False`
132
+ `bool("1")` ==> `True`
133
+ The code
134
+ ```
135
+ if istr("0"):
136
+ print("True")
137
+ else:
138
+ print("False")
139
+ ```
140
+ will print `False`
141
+
142
+ For the in operator, an istr is treated as an ordinary string, although it is possible to use ints as well:
143
+ ```
144
+ "34" in istr(1234)
145
+ 34 in istr(1234)
146
+ ```
147
+ On the left hand side an istr is always treated as a string:
148
+ ```
149
+ istr(1234) in "01234566890ABCDEF"
150
+ ```
151
+
152
+ 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.
153
+ Also divisions are always floor divisions!
154
+
155
+ There's a special case for `istr("")`. This is a proper empty string, but also represents the value of 0.
156
+ That is to allow for `istr("").join(i for i in "01234)"`, resulting in `istr("01234")`.
157
+
158
+ Sorting a list of istrs is based on the integer value, not the string. So
159
+
160
+ `" ".join(sorted("1 3 2 4 5 6 11 7 9 8 10 12 0".split()))`
161
+
162
+ is
163
+
164
+ `"0 1 10 11 2 3 4 5 6 7 8 9"`
165
+
166
+ ,whereas
167
+
168
+ `" ".join(sorted(istr("1 3 2 4 5 6 11 7 9 8 10 12 0".split())))`
169
+
170
+ is
171
+
172
+ `"0 1 2 3 4 5 6 7 8 9 10 11"`
173
+
174
+ # Using other values for istr than numeric value or str
175
+ Apart from with simple numeric (to be interpreted as an int) or str, istr can be initialized with
176
+ several other types:
177
+
178
+ - if a dict (or subtype of dict), the same type dict will be returned with all values istr'ed
179
+
180
+ `istr({0: 0, 1: 1, 2: 4})` ==> `{0: istr("0"), 1: istr("1"), 2: istr("4")}`
181
+
182
+ - if an iterator, the iterator will be mapped with istr
183
+
184
+ `istr(i * i for i in range(3))` ==> `<map object>`
185
+
186
+ `list(istr(i * i for i in range(3)))` ==> `[istr("0"), istr("1"), istr("4")]`
187
+
188
+ - if an iterable, the same type will be returned with all elements istr'ed
189
+
190
+ `istr([0, 1, 4])` ==> `[istr("0"), istr("1"), istr("4")]`
191
+
192
+ `istr((0, 1, 4))` ==> `(istr("0"), istr("1"), istr("4"))`
193
+
194
+ `istr({0, 1, 4})` ==> `{istr("4"), istr("0"), istr("1")} # or similar`
195
+
196
+ - if a range, an istr.range instance will be returned
197
+
198
+ `istr(range(3))` ==> `istr.range(3)`
199
+
200
+ `list(istr(range(3)))` ==> `[istr("0"), istr("1"), istr("2")]`
201
+
202
+ `len(istr(range(3)))` ==> `3`
203
+
204
+ - if an istr.range instance, the same istr.range will be returned
205
+
206
+ # More than one parameter for istr
207
+ It is possible to give more than one parameter, in which case a tuple
208
+ of the istrs of the parameters will be returned, which can be handy
209
+ to unpack multiple values, e.g.
210
+
211
+ `a, b, c = istr(5, 6, 7)` ==> `a=istr("5") , b=istr("6"), c=istr("7")`
212
+
213
+ # test for even/odd
214
+ It is possible to test for even/odd with the
215
+
216
+ `is_even` and `is_odd` method, e.g.
217
+
218
+ ```
219
+ print(istr(4).is_even())
220
+ print(istr(5).is_odd())
221
+ ```
222
+ This will print `True` twice.
223
+
224
+ # reverse an istr
225
+ The method `istr.reversed()` will return the an istr with the reversed content:
226
+ ```
227
+ print(repr(istr(456).reversed()))
228
+ print(repr(istr("0456").reversed()))
229
+ ```
230
+ result:
231
+ ```
232
+ istr("654")
233
+ istr("6540")
234
+ ```
235
+ The same can -of course- be achieved with
236
+ ```
237
+ print(repr(istr(456)[::-1]))
238
+ print(repr(istr("0456")[::-1]))
239
+ ```
240
+ Note that is impossible to reverse a negative istr.
241
+
242
+ # enumerate with istrs
243
+
244
+ The `istr.enumerate` method can be used just as the builtin enumerate function.
245
+ The iteration counter however is an istr rather than an int. E.g.
246
+ ```
247
+ for i,c in istr.enumerate("abc"):
248
+ print(f"{repr(i)} {c}")
249
+ ```
250
+ prints
251
+ ```
252
+ istr('0') a
253
+ istr('1') b
254
+ istr('2') c
255
+ ```
256
+
257
+ # concatenate an iterable
258
+
259
+ The `istr.concat1 method can be useful to map all items of an iterable
260
+ to `istr` and then concatenate these.
261
+
262
+ `list(istr.concat(((1,2),(3,4)))` ==> `istr([12,34])`
263
+
264
+ `list(istr.concat(itertools.permutations(range(3),2)))` ==> `[istr('01'), istr('02'), istr('10'), istr('12'), istr('20'), istr('21')]`
265
+
266
+ # Subclassing istr
267
+ When a class is derived from istr, all methods will return that newly derived class.
268
+
269
+ E.g.
270
+ ```
271
+ class jstr(istr):
272
+ ...
273
+
274
+ print(repr(jstr(4) * jstr(5)))
275
+ ```
276
+ will print `jstr('20')`
277
+
278
+ # Changing the way repr works
279
+
280
+ It is possible to control the way an `istr` instance will be repr'ed.
281
+
282
+ By default, the `istr('5')` is represented as `istr('5')`.
283
+
284
+ With the istr.repr_mode() context manager, that can be changed:
285
+ ```
286
+ with istr.repr_mode("str"):
287
+ five = istr('5')
288
+ print(repr(five))
289
+ with istr.repr_mode("int"):
290
+ five = istr('5')
291
+ print(repr(five))
292
+ with istr.repr_mode("istr"):
293
+ five = istr('5')
294
+ print(repr(five))
295
+ ```
296
+ This will print
297
+ ```
298
+ '5'
299
+ 5
300
+ istr('5')
301
+ ```
302
+ Note that the way an `istr` is represented is determined at initialization.
303
+
304
+ It is also possible to set the repr mode without a context manager:
305
+
306
+ ```
307
+ istr.repr_mode("str")
308
+ five = istr('5')
309
+ print(repr(five))
310
+ ```
311
+ This will print
312
+ ```
313
+ '5'
314
+ ```
315
+ Finally, the current repr mode can be queried with `istr.repr_mode()`. So upon start:
316
+ ```
317
+ print(repr(istr.repr_mode()))
318
+ ```
319
+ will output `istr`.
320
+
321
+ # Changing the base system
322
+
323
+ By default, `istr` works in base 10. However it is possible to change the base system with the `istr.base()` context manager / method.
324
+
325
+ Any base between 2 and 36 may be used.
326
+
327
+ Note that the integer is always stored in base 10 mode, but the string
328
+ representation will reflect the chosen base (at time of initialization).
329
+
330
+ Some examples:
331
+ ```
332
+ with istr.base(16):
333
+ a = istr("7fff")
334
+ print(int(a))
335
+
336
+ b = istr(15)
337
+ print(repr(b))
338
+ ```
339
+ This will result in
340
+ ```
341
+ 32767
342
+ istr('F')
343
+ ```
344
+ All calculations are done in the decimal 10 system.
345
+
346
+ Note that the way an `istr` is interpreted is determined at initialization.
347
+
348
+ It is also possible to set the repr mode without a context manager:
349
+ ```
350
+ istr.base(16)
351
+ print(int(istr("7fff")))
352
+ ```
353
+ This will print
354
+ ```
355
+ 32767
356
+ ```
357
+ Finally, the current base can be queried with `istr.base()`, so upon start:
358
+ ```
359
+ print(istr.base())
360
+ ```
361
+ will result in `10`.
362
+
363
+ # Changing the format of the string
364
+
365
+ By default, `istr` does not change the way an istr is stored when a str is to initialize:
366
+
367
+ `repr('4'))` ==> `istr('4')`
368
+
369
+ `repr(' 4'))` ==> `istr(' 4')`
370
+
371
+ `repr('4 '))` ==> `istr('4 ')`
372
+
373
+ For initializing with an int (or other numeric) value, the string is simply the str representation
374
+
375
+ `repr(4))` ==> `istr('4')`
376
+
377
+ With the `istr.format()` context manager this behavior can be changed.
378
+ If the format specifier is a number, most likely a single digit, that
379
+ will be the minimum number of characters in the string:
380
+ ```
381
+ with istr.format("3"):
382
+ print(repr(istr(1)))
383
+ print(repr(istr(12)))
384
+ print(repr(istr(123)))
385
+ print(repr(istr(1234)))
386
+ ```
387
+ will print
388
+ ```
389
+ istr(' 1')
390
+ istr(' 12')
391
+ istr('123')
392
+ istr('1234')
393
+ ```
394
+ If the string starts with a `0`, the string will be zero filled:
395
+ ```
396
+ with istr.format("03"):
397
+ print(repr(istr(1)))
398
+ print(repr(istr(12)))
399
+ print(repr(istr(123)))
400
+ print(repr(istr(1234)))
401
+ ```
402
+ will print
403
+ ```
404
+ istr('001')
405
+ istr('012')
406
+ istr('123')
407
+ istr('1234')
408
+ ```
409
+ Note that if a format other than the default `''` is used, the string will reformatted even if the `istr` is specified with a string:
410
+ ```
411
+ with istr.format("03"):
412
+ print(repr(istr(" 12 ")))
413
+ ```
414
+ will result in `istr('0012')`
415
+
416
+ Remark: For bases other than 10, the string will never be reformatted!
417
+
418
+ # Test script
419
+ There's an extensive pytest script in the `\tests` directory.
420
+
421
+ This script also shows clearly the ways istr can be used.