summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--string_utils.py73
1 files changed, 42 insertions, 31 deletions
diff --git a/string_utils.py b/string_utils.py
index 6eda278..244c450 100644
--- a/string_utils.py
+++ b/string_utils.py
@@ -11,7 +11,16 @@ import numbers
import random
import re
import string
-from typing import Any, Callable, Dict, Iterable, List, Optional, Sequence, Tuple
+from typing import (
+ Any,
+ Callable,
+ Dict,
+ Iterable,
+ List,
+ Optional,
+ Sequence,
+ Tuple,
+)
import unicodedata
from uuid import uuid4
import warnings
@@ -32,7 +41,7 @@ URLS_RAW_STRING = (
r"([a-z-]+://)" # scheme
r"([a-z_\d-]+:[a-z_\d-]+@)?" # user:password
r"(www\.)?" # www.
- r"((?<!\.)[a-z\d]+[a-z\d.-]+\.[a-z]{2,6}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|localhost)" # domain
+ r"((?<!\.)[a-z\d]+[a-z\d.-]+\.[a-z]{2,6}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|localhost)" # domain
r"(:\d{2,})?" # port number
r"(/[a-z\d_%+-]*)*" # folders
r"(\.[a-z\d_%+-]+)*" # file extension
@@ -254,10 +263,10 @@ def is_integer_number(in_str: str) -> bool:
False
"""
return (
- (is_number(in_str) and "." not in in_str) or
- is_hexidecimal_integer_number(in_str) or
- is_octal_integer_number(in_str) or
- is_binary_integer_number(in_str)
+ (is_number(in_str) and "." not in in_str)
+ or is_hexidecimal_integer_number(in_str)
+ or is_octal_integer_number(in_str)
+ or is_binary_integer_number(in_str)
)
@@ -382,10 +391,7 @@ def strip_escape_sequences(in_str: str) -> str:
def add_thousands_separator(
- in_str: str,
- *,
- separator_char = ',',
- places = 3
+ in_str: str, *, separator_char=',', places=3
) -> str:
"""
Add thousands separator to a numeric string. Also handles numbers.
@@ -406,20 +412,21 @@ def add_thousands_separator(
in_str = f'{in_str}'
if is_number(in_str):
return _add_thousands_separator(
- in_str,
- separator_char = separator_char,
- places = places
+ in_str, separator_char=separator_char, places=places
)
raise ValueError(in_str)
-def _add_thousands_separator(in_str: str, *, separator_char = ',', places = 3) -> str:
+def _add_thousands_separator(
+ in_str: str, *, separator_char=',', places=3
+) -> str:
decimal_part = ""
if '.' in in_str:
(in_str, decimal_part) = in_str.split('.')
tmp = [iter(in_str[::-1])] * places
ret = separator_char.join(
- "".join(x) for x in zip_longest(*tmp, fillvalue=""))[::-1]
+ "".join(x) for x in zip_longest(*tmp, fillvalue="")
+ )[::-1]
if len(decimal_part) > 0:
ret += '.'
ret += decimal_part
@@ -507,6 +514,7 @@ def suffix_string_to_number(in_str: str) -> Optional[int]:
>>> suffix_string_to_number('13.1Gb')
14066017894
"""
+
def suffix_capitalize(s: str) -> str:
if len(s) == 1:
return s.upper()
@@ -1093,6 +1101,7 @@ def to_date(in_str: str) -> Optional[datetime.date]:
Parses a date string. See DateParser docs for details.
"""
import dateparse.dateparse_utils as dp
+
try:
d = dp.DateParser()
d.parse(in_str)
@@ -1108,6 +1117,7 @@ def valid_date(in_str: str) -> bool:
True if the string represents a valid date.
"""
import dateparse.dateparse_utils as dp
+
try:
d = dp.DateParser()
_ = d.parse(in_str)
@@ -1123,6 +1133,7 @@ def to_datetime(in_str: str) -> Optional[datetime.datetime]:
Parses a datetime string. See DateParser docs for more info.
"""
import dateparse.dateparse_utils as dp
+
try:
d = dp.DateParser()
dt = d.parse(in_str)
@@ -1160,7 +1171,7 @@ def squeeze(in_str: str, character_to_squeeze: str = ' ') -> str:
return re.sub(
r'(' + re.escape(character_to_squeeze) + r')+',
character_to_squeeze,
- in_str
+ in_str,
)
@@ -1232,6 +1243,7 @@ class SprintfStdout(object):
'test\n'
"""
+
def __init__(self) -> None:
self.destination = io.StringIO()
self.recorder = None
@@ -1331,9 +1343,7 @@ def trigrams(txt: str):
def shuffle_columns_into_list(
- input_lines: Iterable[str],
- column_specs: Iterable[Iterable[int]],
- delim=''
+ input_lines: Iterable[str], column_specs: Iterable[Iterable[int]], delim=''
) -> Iterable[str]:
"""Helper to shuffle / parse columnar data and return the results as a
list. The column_specs argument is an iterable collection of
@@ -1363,9 +1373,9 @@ def shuffle_columns_into_list(
def shuffle_columns_into_dict(
- input_lines: Iterable[str],
- column_specs: Iterable[Tuple[str, Iterable[int]]],
- delim=''
+ input_lines: Iterable[str],
+ column_specs: Iterable[Tuple[str, Iterable[int]]],
+ delim='',
) -> Dict[str, str]:
"""Helper to shuffle / parse columnar data and return the results
as a dict.
@@ -1475,10 +1485,12 @@ def chunk(txt: str, chunk_size):
logger.warning(msg)
warnings.warn(msg, stacklevel=2)
for x in range(0, len(txt), chunk_size):
- yield txt[x:x+chunk_size]
+ yield txt[x : x + chunk_size]
-def to_bitstring(txt: str, *, delimiter='', encoding='utf-8', errors='surrogatepass') -> str:
+def to_bitstring(
+ txt: str, *, delimiter='', encoding='utf-8', errors='surrogatepass'
+) -> str:
"""Encode txt and then chop it into bytes. Note: only bitstrings
with delimiter='' are interpretable by from_bitstring.
@@ -1493,12 +1505,7 @@ def to_bitstring(txt: str, *, delimiter='', encoding='utf-8', errors='surrogatep
"""
etxt = to_ascii(txt)
- bits = bin(
- int.from_bytes(
- etxt,
- 'big'
- )
- )
+ bits = bin(int.from_bytes(etxt, 'big'))
bits = bits[2:]
return delimiter.join(chunk(bits.zfill(8 * ((len(bits) + 7) // 8)), 8))
@@ -1524,7 +1531,10 @@ def from_bitstring(bits: str, encoding='utf-8', errors='surrogatepass') -> str:
"""
n = int(bits, 2)
- return n.to_bytes((n.bit_length() + 7) // 8, 'big').decode(encoding, errors) or '\0'
+ return (
+ n.to_bytes((n.bit_length() + 7) // 8, 'big').decode(encoding, errors)
+ or '\0'
+ )
def ip_v4_sort_key(txt: str) -> Tuple[int]:
@@ -1574,4 +1584,5 @@ def replace_all(in_str: str, replace_set: str, replacement: str) -> str:
if __name__ == '__main__':
import doctest
+
doctest.testmod()