absfuyu 4.2.0__py3-none-any.whl → 5.0.0__py3-none-any.whl
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.
Potentially problematic release.
This version of absfuyu might be problematic. Click here for more details.
- absfuyu/__init__.py +4 -4
- absfuyu/__main__.py +13 -1
- absfuyu/cli/color.py +7 -0
- absfuyu/cli/do_group.py +0 -35
- absfuyu/cli/tool_group.py +5 -5
- absfuyu/config/__init__.py +17 -34
- absfuyu/core/__init__.py +49 -0
- absfuyu/core/baseclass.py +299 -0
- absfuyu/core/baseclass2.py +165 -0
- absfuyu/core/decorator.py +67 -0
- absfuyu/core/docstring.py +163 -0
- absfuyu/core/dummy_cli.py +67 -0
- absfuyu/core/dummy_func.py +47 -0
- absfuyu/dxt/__init__.py +42 -0
- absfuyu/dxt/dictext.py +201 -0
- absfuyu/dxt/dxt_support.py +79 -0
- absfuyu/dxt/intext.py +586 -0
- absfuyu/dxt/listext.py +508 -0
- absfuyu/dxt/strext.py +530 -0
- absfuyu/{extensions → extra}/__init__.py +2 -2
- absfuyu/extra/beautiful.py +251 -0
- absfuyu/{extensions → extra}/data_analysis.py +51 -82
- absfuyu/fun/__init__.py +110 -135
- absfuyu/fun/tarot.py +9 -17
- absfuyu/game/__init__.py +6 -0
- absfuyu/game/game_stat.py +6 -0
- absfuyu/game/sudoku.py +7 -1
- absfuyu/game/tictactoe.py +12 -5
- absfuyu/game/wordle.py +14 -8
- absfuyu/general/__init__.py +6 -79
- absfuyu/general/content.py +22 -36
- absfuyu/general/generator.py +17 -42
- absfuyu/general/human.py +108 -228
- absfuyu/general/shape.py +1334 -0
- absfuyu/logger.py +8 -13
- absfuyu/pkg_data/__init__.py +136 -99
- absfuyu/pkg_data/deprecated.py +133 -0
- absfuyu/sort.py +6 -130
- absfuyu/tools/__init__.py +2 -2
- absfuyu/tools/checksum.py +33 -22
- absfuyu/tools/converter.py +51 -48
- absfuyu/tools/keygen.py +25 -30
- absfuyu/tools/obfuscator.py +246 -112
- absfuyu/tools/passwordlib.py +99 -29
- absfuyu/tools/shutdownizer.py +68 -47
- absfuyu/tools/web.py +2 -9
- absfuyu/util/__init__.py +15 -15
- absfuyu/util/api.py +10 -15
- absfuyu/util/json_method.py +7 -24
- absfuyu/util/lunar.py +3 -9
- absfuyu/util/path.py +22 -27
- absfuyu/util/performance.py +43 -67
- absfuyu/util/shorten_number.py +65 -14
- absfuyu/util/zipped.py +9 -15
- {absfuyu-4.2.0.dist-info → absfuyu-5.0.0.dist-info}/METADATA +41 -14
- absfuyu-5.0.0.dist-info/RECORD +68 -0
- absfuyu/core.py +0 -57
- absfuyu/everything.py +0 -32
- absfuyu/extensions/beautiful.py +0 -188
- absfuyu/fun/WGS.py +0 -134
- absfuyu/general/data_extension.py +0 -1796
- absfuyu/tools/stats.py +0 -226
- absfuyu/util/pkl.py +0 -67
- absfuyu-4.2.0.dist-info/RECORD +0 -59
- {absfuyu-4.2.0.dist-info → absfuyu-5.0.0.dist-info}/WHEEL +0 -0
- {absfuyu-4.2.0.dist-info → absfuyu-5.0.0.dist-info}/entry_points.txt +0 -0
- {absfuyu-4.2.0.dist-info → absfuyu-5.0.0.dist-info}/licenses/LICENSE +0 -0
absfuyu/dxt/strext.py
ADDED
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Absfuyu: Data Extension
|
|
3
|
+
-----------------------
|
|
4
|
+
str extension
|
|
5
|
+
|
|
6
|
+
Version: 5.0.0
|
|
7
|
+
Date updated: 11/02/2025 (dd/mm/yyyy)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
# Module Package
|
|
11
|
+
# ---------------------------------------------------------------------------
|
|
12
|
+
__all__ = ["Text", "TextAnalyzeDictFormat"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Library
|
|
16
|
+
# ---------------------------------------------------------------------------
|
|
17
|
+
import random
|
|
18
|
+
from typing import NotRequired, Self, TypedDict
|
|
19
|
+
|
|
20
|
+
from absfuyu.core import ShowAllMethodsMixin, deprecated, versionadded, versionchanged
|
|
21
|
+
from absfuyu.general.generator import Charset, Generator
|
|
22
|
+
from absfuyu.logger import logger
|
|
23
|
+
from absfuyu.util import set_min_max
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# Class
|
|
27
|
+
# ---------------------------------------------------------------------------
|
|
28
|
+
class TextAnalyzeDictFormat(TypedDict):
|
|
29
|
+
"""
|
|
30
|
+
Dict format for ``Text.analyze()`` method
|
|
31
|
+
|
|
32
|
+
Parameters
|
|
33
|
+
----------
|
|
34
|
+
digit : int
|
|
35
|
+
Number of digit characters
|
|
36
|
+
|
|
37
|
+
uppercase : int
|
|
38
|
+
Number of uppercase characters
|
|
39
|
+
|
|
40
|
+
lowercase : int
|
|
41
|
+
Number of lowercase characters
|
|
42
|
+
|
|
43
|
+
other : int
|
|
44
|
+
Number of other printable characters
|
|
45
|
+
|
|
46
|
+
is_pangram : NotRequired[bool]
|
|
47
|
+
Is a pangram (Not required)
|
|
48
|
+
|
|
49
|
+
is_palindrome : NotRequired[bool]
|
|
50
|
+
Is a palindrome (Not required)
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
digit: int
|
|
54
|
+
uppercase: int
|
|
55
|
+
lowercase: int
|
|
56
|
+
other: int
|
|
57
|
+
is_pangram: NotRequired[bool]
|
|
58
|
+
is_palindrome: NotRequired[bool]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class Text(ShowAllMethodsMixin, str):
|
|
62
|
+
"""
|
|
63
|
+
``str`` extension
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
def divide(self, string_split_size: int = 60) -> list[str]:
|
|
67
|
+
"""
|
|
68
|
+
Divide long string into smaller size
|
|
69
|
+
|
|
70
|
+
Parameters
|
|
71
|
+
----------
|
|
72
|
+
string_split_size : int
|
|
73
|
+
Divide string every ``x`` character
|
|
74
|
+
(Default: ``60``)
|
|
75
|
+
|
|
76
|
+
Returns
|
|
77
|
+
-------
|
|
78
|
+
list[str]
|
|
79
|
+
A list in which each item is a smaller
|
|
80
|
+
string with the size of ``string_split_size``
|
|
81
|
+
(need to be concaternate later)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
Example:
|
|
85
|
+
--------
|
|
86
|
+
>>> test = Text("This is an extremely long line of text!")
|
|
87
|
+
>>> test.divide(string_split_size=20)
|
|
88
|
+
['This is an extremely', ' long line of text!']
|
|
89
|
+
"""
|
|
90
|
+
temp = str(self)
|
|
91
|
+
output = []
|
|
92
|
+
while len(temp) != 0:
|
|
93
|
+
output.append(temp[:string_split_size])
|
|
94
|
+
temp = temp[string_split_size:]
|
|
95
|
+
return output
|
|
96
|
+
|
|
97
|
+
def divide_with_variable(
|
|
98
|
+
self,
|
|
99
|
+
split_size: int = 60,
|
|
100
|
+
split_var_len: int = 12,
|
|
101
|
+
custom_var_name: str | None = None,
|
|
102
|
+
) -> list[str]:
|
|
103
|
+
"""
|
|
104
|
+
Divide long string into smaller size,
|
|
105
|
+
then assign a random variable to splited
|
|
106
|
+
string for later use
|
|
107
|
+
|
|
108
|
+
Parameters
|
|
109
|
+
----------
|
|
110
|
+
split_size : int
|
|
111
|
+
Divide string every ``x`` character
|
|
112
|
+
(Default: ``60``)
|
|
113
|
+
|
|
114
|
+
split_var_len : int
|
|
115
|
+
Length of variable name assigned to each item
|
|
116
|
+
(Default: ``12``)
|
|
117
|
+
|
|
118
|
+
custom_var_name : str
|
|
119
|
+
Custom variable name when join string
|
|
120
|
+
|
|
121
|
+
Returns
|
|
122
|
+
-------
|
|
123
|
+
list[str]
|
|
124
|
+
A list in which each item is a smaller
|
|
125
|
+
string with the size of ``split_size``
|
|
126
|
+
and a way to concaternate them (when using ``print()``)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
Example:
|
|
130
|
+
--------
|
|
131
|
+
>>> test = Text("This is an extremely long line of text!")
|
|
132
|
+
>>> test.divide_with_variable(split_size=20)
|
|
133
|
+
[
|
|
134
|
+
"qNTCnmkFPTJg='This is an extremely'",
|
|
135
|
+
"vkmLBUykYYDG=' long line of text!'",
|
|
136
|
+
'sBoSwEfoxBIH=qNTCnmkFPTJg+vkmLBUykYYDG',
|
|
137
|
+
'sBoSwEfoxBIH'
|
|
138
|
+
]
|
|
139
|
+
|
|
140
|
+
>>> test = Text("This is an extremely long line of text!")
|
|
141
|
+
>>> test.divide_with_variable(split_size=20, custom_var_name="test")
|
|
142
|
+
[
|
|
143
|
+
"test1='This is an extremely'",
|
|
144
|
+
"test2=' long line of text!'",
|
|
145
|
+
'test=test1+test2',
|
|
146
|
+
'test'
|
|
147
|
+
]
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
temp = self.divide(split_size)
|
|
151
|
+
output = []
|
|
152
|
+
|
|
153
|
+
# split variable
|
|
154
|
+
splt_len = len(temp)
|
|
155
|
+
|
|
156
|
+
if custom_var_name is None:
|
|
157
|
+
splt_name = Generator.generate_string(
|
|
158
|
+
charset=Charset.ALPHABET, size=split_var_len, times=splt_len + 1
|
|
159
|
+
)
|
|
160
|
+
for i in range(splt_len):
|
|
161
|
+
output.append(f"{splt_name[i]}='{temp[i]}'")
|
|
162
|
+
else:
|
|
163
|
+
for i in range(splt_len):
|
|
164
|
+
output.append(f"{custom_var_name}{i + 1}='{temp[i]}'")
|
|
165
|
+
|
|
166
|
+
# joined variable
|
|
167
|
+
temp = []
|
|
168
|
+
if custom_var_name is None:
|
|
169
|
+
for i in range(splt_len):
|
|
170
|
+
if i == 0:
|
|
171
|
+
temp.append(f"{splt_name[-1]}=")
|
|
172
|
+
if i == splt_len - 1:
|
|
173
|
+
temp.append(f"{splt_name[i]}")
|
|
174
|
+
else:
|
|
175
|
+
temp.append(f"{splt_name[i]}+")
|
|
176
|
+
else:
|
|
177
|
+
for i in range(splt_len):
|
|
178
|
+
if i == 0:
|
|
179
|
+
temp.append(f"{custom_var_name}=")
|
|
180
|
+
if i == splt_len - 1:
|
|
181
|
+
temp.append(f"{custom_var_name}{i + 1}")
|
|
182
|
+
else:
|
|
183
|
+
temp.append(f"{custom_var_name}{i + 1}+")
|
|
184
|
+
|
|
185
|
+
output.append("".join(temp))
|
|
186
|
+
if custom_var_name is None:
|
|
187
|
+
output.append(splt_name[-1])
|
|
188
|
+
else:
|
|
189
|
+
output.append(custom_var_name)
|
|
190
|
+
|
|
191
|
+
return output
|
|
192
|
+
|
|
193
|
+
@versionchanged("3.3.0", reason="Updated functionality")
|
|
194
|
+
def analyze(self, full: bool = False) -> TextAnalyzeDictFormat:
|
|
195
|
+
"""
|
|
196
|
+
String analyze (count number of type of character)
|
|
197
|
+
|
|
198
|
+
Parameters
|
|
199
|
+
----------
|
|
200
|
+
full : bool
|
|
201
|
+
Full analyze when ``True``
|
|
202
|
+
(Default: ``False``)
|
|
203
|
+
|
|
204
|
+
Returns
|
|
205
|
+
-------
|
|
206
|
+
dict | TextAnalyzeDictFormat
|
|
207
|
+
A dictionary contains number of digit character,
|
|
208
|
+
uppercase character, lowercase character, and
|
|
209
|
+
special character
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
Example:
|
|
213
|
+
--------
|
|
214
|
+
>>> test = Text("Random T3xt!")
|
|
215
|
+
>>> test.analyze()
|
|
216
|
+
{'digit': 1, 'uppercase': 2, 'lowercase': 7, 'other': 2}
|
|
217
|
+
"""
|
|
218
|
+
|
|
219
|
+
temp = self
|
|
220
|
+
|
|
221
|
+
detail: TextAnalyzeDictFormat = {
|
|
222
|
+
"digit": 0,
|
|
223
|
+
"uppercase": 0,
|
|
224
|
+
"lowercase": 0,
|
|
225
|
+
"other": 0,
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
for x in temp:
|
|
229
|
+
if ord(x) in range(48, 58): # num
|
|
230
|
+
detail["digit"] += 1
|
|
231
|
+
elif ord(x) in range(65, 91): # cap
|
|
232
|
+
detail["uppercase"] += 1
|
|
233
|
+
elif ord(x) in range(97, 123): # low
|
|
234
|
+
detail["lowercase"] += 1
|
|
235
|
+
else:
|
|
236
|
+
detail["other"] += 1
|
|
237
|
+
|
|
238
|
+
if full:
|
|
239
|
+
detail["is_palindrome"] = self.is_palindrome()
|
|
240
|
+
detail["is_pangram"] = self.is_pangram()
|
|
241
|
+
|
|
242
|
+
return detail
|
|
243
|
+
|
|
244
|
+
def reverse(self) -> Self:
|
|
245
|
+
"""
|
|
246
|
+
Reverse the string
|
|
247
|
+
|
|
248
|
+
Returns
|
|
249
|
+
-------
|
|
250
|
+
Text
|
|
251
|
+
Reversed string
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
Example:
|
|
255
|
+
--------
|
|
256
|
+
>>> test = Text("Hello, World!")
|
|
257
|
+
>>> test.reverse()
|
|
258
|
+
'!dlroW ,olleH'
|
|
259
|
+
"""
|
|
260
|
+
return self.__class__(self[::-1])
|
|
261
|
+
|
|
262
|
+
@versionchanged("5.0.0", reason="Add ``custom_alphabet`` parameter")
|
|
263
|
+
def is_pangram(self, custom_alphabet: set[str] | None = None) -> bool:
|
|
264
|
+
"""
|
|
265
|
+
Check if string is a pangram
|
|
266
|
+
|
|
267
|
+
A pangram is a unique sentence in which
|
|
268
|
+
every letter of the alphabet is used at least once
|
|
269
|
+
|
|
270
|
+
Parameters
|
|
271
|
+
----------
|
|
272
|
+
custom_alphabet : set[str] | None, optional
|
|
273
|
+
Custom alphabet to use
|
|
274
|
+
(Default: ``None``)
|
|
275
|
+
|
|
276
|
+
Returns
|
|
277
|
+
-------
|
|
278
|
+
bool
|
|
279
|
+
| ``True`` if string is a pangram
|
|
280
|
+
| ``False`` if string is not a pangram
|
|
281
|
+
"""
|
|
282
|
+
text = self
|
|
283
|
+
if custom_alphabet is None:
|
|
284
|
+
alphabet = set("abcdefghijklmnopqrstuvwxyz")
|
|
285
|
+
else:
|
|
286
|
+
alphabet = custom_alphabet
|
|
287
|
+
return not set(alphabet) - set(text.lower())
|
|
288
|
+
|
|
289
|
+
def is_palindrome(self) -> bool:
|
|
290
|
+
"""
|
|
291
|
+
Check if string is a palindrome
|
|
292
|
+
|
|
293
|
+
A palindrome is a word, verse, or sentence
|
|
294
|
+
or a number that reads the same backward or forward
|
|
295
|
+
|
|
296
|
+
Returns
|
|
297
|
+
-------
|
|
298
|
+
bool
|
|
299
|
+
| ``True`` if string is a palindrome
|
|
300
|
+
| ``False`` if string is not a palindrome
|
|
301
|
+
"""
|
|
302
|
+
text = self
|
|
303
|
+
# Use string slicing [start:end:step]
|
|
304
|
+
return text == text[::-1]
|
|
305
|
+
|
|
306
|
+
def to_hex(self, raw: bool = False) -> str:
|
|
307
|
+
r"""
|
|
308
|
+
Convert string to hex form
|
|
309
|
+
|
|
310
|
+
Parameters
|
|
311
|
+
----------
|
|
312
|
+
raw : bool
|
|
313
|
+
| ``False``: hex string in the form of ``\x`` (default)
|
|
314
|
+
| ``True``: normal hex string
|
|
315
|
+
|
|
316
|
+
Returns
|
|
317
|
+
-------
|
|
318
|
+
str
|
|
319
|
+
Hexed string
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
Example:
|
|
323
|
+
--------
|
|
324
|
+
>>> test = Text("Hello, World!")
|
|
325
|
+
>>> test.to_hex()
|
|
326
|
+
'\\x48\\x65\\x6c\\x6c\\x6f\\x2c\\x20\\x57\\x6f\\x72\\x6c\\x64\\x21'
|
|
327
|
+
"""
|
|
328
|
+
text = self
|
|
329
|
+
|
|
330
|
+
byte_str = text.encode("utf-8")
|
|
331
|
+
# hex_str = byte_str.hex()
|
|
332
|
+
|
|
333
|
+
if raw:
|
|
334
|
+
return byte_str.hex()
|
|
335
|
+
|
|
336
|
+
temp = byte_str.hex("x")
|
|
337
|
+
return "\\x" + temp.replace("x", "\\x")
|
|
338
|
+
|
|
339
|
+
def random_capslock(self, probability: int = 50) -> Self:
|
|
340
|
+
"""
|
|
341
|
+
Randomly capslock letter in string
|
|
342
|
+
|
|
343
|
+
Parameters
|
|
344
|
+
----------
|
|
345
|
+
probability : int
|
|
346
|
+
Probability in range [0, 100]
|
|
347
|
+
(Default: ``50``)
|
|
348
|
+
|
|
349
|
+
Returns
|
|
350
|
+
-------
|
|
351
|
+
Text
|
|
352
|
+
Random capslocked text
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
Example:
|
|
356
|
+
--------
|
|
357
|
+
>>> test = Text("This is an extremely long line of text!")
|
|
358
|
+
>>> test.random_capslock()
|
|
359
|
+
'tHis iS An ExtREmELY loNg liNE oF tExT!'
|
|
360
|
+
"""
|
|
361
|
+
probability = int(set_min_max(probability))
|
|
362
|
+
text = self.lower()
|
|
363
|
+
|
|
364
|
+
temp = []
|
|
365
|
+
for x in text:
|
|
366
|
+
if random.randint(1, 100) <= probability:
|
|
367
|
+
x = x.upper()
|
|
368
|
+
temp.append(x)
|
|
369
|
+
logger.debug(temp)
|
|
370
|
+
return self.__class__("".join(temp))
|
|
371
|
+
|
|
372
|
+
@versionchanged("5.0.0", reason="Use ``str.swapcase()``")
|
|
373
|
+
def reverse_capslock(self) -> Self:
|
|
374
|
+
"""
|
|
375
|
+
Reverse capslock in string
|
|
376
|
+
|
|
377
|
+
Returns
|
|
378
|
+
-------
|
|
379
|
+
Text
|
|
380
|
+
Reversed capslock ``Text``
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
Example:
|
|
384
|
+
--------
|
|
385
|
+
>>> test = Text("Foo")
|
|
386
|
+
>>> test.reverse_capslock()
|
|
387
|
+
'fOO'
|
|
388
|
+
"""
|
|
389
|
+
return self.__class__(self.swapcase())
|
|
390
|
+
|
|
391
|
+
def to_list(self) -> list[str]:
|
|
392
|
+
"""
|
|
393
|
+
Convert into list
|
|
394
|
+
|
|
395
|
+
Returns
|
|
396
|
+
-------
|
|
397
|
+
list[str]
|
|
398
|
+
List of string
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
Example:
|
|
402
|
+
--------
|
|
403
|
+
>>> test = Text("test")
|
|
404
|
+
>>> test.to_list()
|
|
405
|
+
['t', 'e', 's', 't']
|
|
406
|
+
"""
|
|
407
|
+
return list(self)
|
|
408
|
+
|
|
409
|
+
@deprecated("5.0.0", reason="Unused")
|
|
410
|
+
def to_listext(self) -> None:
|
|
411
|
+
"""Deprecated, will be removed soon"""
|
|
412
|
+
raise NotImplementedError("Deprecated, will be removed soon")
|
|
413
|
+
|
|
414
|
+
@versionadded("3.3.0")
|
|
415
|
+
def count_pattern(self, pattern: str, ignore_capslock: bool = False) -> int:
|
|
416
|
+
"""
|
|
417
|
+
Returns how many times ``pattern`` appears in text
|
|
418
|
+
|
|
419
|
+
Parameters
|
|
420
|
+
----------
|
|
421
|
+
pattern : str
|
|
422
|
+
Pattern to count
|
|
423
|
+
|
|
424
|
+
ignore_capslock : bool
|
|
425
|
+
Ignore the pattern uppercase or lowercase
|
|
426
|
+
(Default: ``False`` - Exact match)
|
|
427
|
+
|
|
428
|
+
Returns
|
|
429
|
+
-------
|
|
430
|
+
int
|
|
431
|
+
How many times pattern appeared
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
Example:
|
|
435
|
+
--------
|
|
436
|
+
>>> Text("test").count_pattern("t")
|
|
437
|
+
2
|
|
438
|
+
"""
|
|
439
|
+
if len(pattern) > len(self):
|
|
440
|
+
raise ValueError(f"len(<pattern>) must not larger than {len(self)}")
|
|
441
|
+
|
|
442
|
+
temp = str(self)
|
|
443
|
+
if ignore_capslock:
|
|
444
|
+
pattern = pattern.lower()
|
|
445
|
+
temp = temp.lower()
|
|
446
|
+
|
|
447
|
+
out = [
|
|
448
|
+
1
|
|
449
|
+
for i in range(len(temp) - len(pattern) + 1)
|
|
450
|
+
if temp[i : i + len(pattern)] == pattern
|
|
451
|
+
]
|
|
452
|
+
return sum(out)
|
|
453
|
+
|
|
454
|
+
@versionadded("3.3.0")
|
|
455
|
+
def hapax(self, strict: bool = False) -> list[str]:
|
|
456
|
+
"""
|
|
457
|
+
A hapax legomenon (often abbreviated to hapax)
|
|
458
|
+
is a word which occurs only once in either
|
|
459
|
+
the written record of a language, the works of
|
|
460
|
+
an author, or in a single text.
|
|
461
|
+
|
|
462
|
+
This function returns a list of hapaxes (if any)
|
|
463
|
+
(Lettercase is ignored)
|
|
464
|
+
|
|
465
|
+
Parameters
|
|
466
|
+
----------
|
|
467
|
+
strict : bool
|
|
468
|
+
Remove all special characters before checking for hapax
|
|
469
|
+
(Default: ``False``)
|
|
470
|
+
|
|
471
|
+
Returns
|
|
472
|
+
-------
|
|
473
|
+
list[str]
|
|
474
|
+
A list of hapaxes
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
Example:
|
|
478
|
+
--------
|
|
479
|
+
>>> test = Text("A a. a, b c c= C| d d")
|
|
480
|
+
>>> test.hapax()
|
|
481
|
+
['a', 'a.', 'a,', 'b', 'c', 'c=', 'c|']
|
|
482
|
+
|
|
483
|
+
>>> test.hapax(strict=True)
|
|
484
|
+
['b']
|
|
485
|
+
"""
|
|
486
|
+
word_list: list[str] = self.lower().split()
|
|
487
|
+
if strict:
|
|
488
|
+
remove_characters: list[str] = list(r"\"'.,:;|()[]{}\/!@#$%^&*-_=+?<>`~")
|
|
489
|
+
temp = str(self)
|
|
490
|
+
for x in remove_characters:
|
|
491
|
+
temp = temp.replace(x, "")
|
|
492
|
+
word_list = temp.lower().split()
|
|
493
|
+
|
|
494
|
+
hapaxes = filter(lambda x: word_list.count(x) == 1, word_list)
|
|
495
|
+
return list(hapaxes)
|
|
496
|
+
|
|
497
|
+
@versionadded("5.0.0")
|
|
498
|
+
def shorten(self, shorten_size: int = 60) -> str:
|
|
499
|
+
"""
|
|
500
|
+
Shorten long text
|
|
501
|
+
|
|
502
|
+
Parameters
|
|
503
|
+
----------
|
|
504
|
+
shorten_size : int, optional
|
|
505
|
+
How many characters per line.
|
|
506
|
+
Minimum is ``1``, by default ``60``
|
|
507
|
+
|
|
508
|
+
Returns
|
|
509
|
+
-------
|
|
510
|
+
str
|
|
511
|
+
Shortened text
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
Example:
|
|
515
|
+
--------
|
|
516
|
+
>>> test = Text("a" * 200)
|
|
517
|
+
>>> test.shorten()
|
|
518
|
+
(
|
|
519
|
+
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
|
|
520
|
+
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
|
|
521
|
+
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
|
|
522
|
+
'aaaaaaaaaaaaaaaaaaaa'
|
|
523
|
+
)
|
|
524
|
+
"""
|
|
525
|
+
shorten_text_list: list[str] = self.divide(
|
|
526
|
+
string_split_size=max(1, shorten_size)
|
|
527
|
+
)
|
|
528
|
+
shorten_text_list = [repr(x) for x in shorten_text_list]
|
|
529
|
+
out = "(\n" + "\n".join(shorten_text_list) + "\n)"
|
|
530
|
+
return out
|