-
Notifications
You must be signed in to change notification settings - Fork 128
Expand file tree
/
Copy pathstring_utils.py
More file actions
192 lines (136 loc) · 4.92 KB
/
string_utils.py
File metadata and controls
192 lines (136 loc) · 4.92 KB
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
"""Provides string utility functions.
This module offers a collection of string utility functions built on the Rich library.
These utilities are designed to correctly handle strings with ANSI style sequences and
full-width characters (like those used in CJK languages).
"""
from collections.abc import (
Sequence,
)
from rich.align import AlignMethod
from rich.style import StyleType
from rich.text import Text
from . import rich_utils as ru
def align(
val: str,
align: AlignMethod,
width: int | None = None,
character: str = " ",
) -> str:
"""Align string to a given width.
There are convenience wrappers around this function: align_left(), align_center(), and align_right()
:param val: string to align
:param align: one of "left", "center", or "right".
:param width: Desired width. Defaults to width of the terminal.
:param character: Character to pad with. Defaults to " ".
"""
if width is None:
width = ru.console_width()
text = Text.from_ansi(val)
text.align(align, width=width, character=character)
return ru.rich_text_to_string(text)
def align_left(
val: str,
width: int | None = None,
character: str = " ",
) -> str:
"""Left-align string to a given width.
:param val: string to align
:param width: Desired width. Defaults to width of the terminal.
:param character: Character to pad with. Defaults to " ".
"""
return align(val, "left", width=width, character=character)
def align_center(
val: str,
width: int | None = None,
character: str = " ",
) -> str:
"""Center-align string to a given width.
:param val: string to align
:param width: Desired width. Defaults to width of the terminal.
:param character: Character to pad with. Defaults to " ".
"""
return align(val, "center", width=width, character=character)
def align_right(
val: str,
width: int | None = None,
character: str = " ",
) -> str:
"""Right-align string to a given width.
:param val: string to align
:param width: Desired width. Defaults to width of the terminal.
:param character: Character to pad with. Defaults to " ".
"""
return align(val, "right", width=width, character=character)
def stylize(val: str, style: StyleType) -> str:
"""Apply an ANSI style to a string, preserving any existing styles.
:param val: string to be styled
:param style: style instance or style definition to apply.
:return: the stylized string
"""
# Convert to a Rich Text object to parse and preserve existing ANSI styles.
text = Text.from_ansi(val)
text.stylize(style)
return ru.rich_text_to_string(text)
def strip_style(val: str) -> str:
"""Strip all ANSI style sequences (colors, bold, etc.) from a string.
This targets SGR sequences specifically and leaves other terminal
control codes intact.
:param val: string to be stripped
:return: the stripped string
"""
return ru.ANSI_STYLE_SEQUENCE_RE.sub("", val)
def str_width(val: str) -> int:
"""Return the display width of a string.
This is intended for single-line strings.
Replace tabs with spaces before calling this.
:param val: the string being measured
:return: width of the string when printed to the terminal
"""
text = Text.from_ansi(val)
return text.cell_len
def is_quoted(val: str) -> bool:
"""Check if a string is quoted.
:param val: the string being checked for quotes
:return: True if a string is quoted
"""
from . import constants
return len(val) > 1 and val[0] == val[-1] and val[0] in constants.QUOTES
def quote(val: str) -> str:
"""Quote a string."""
quote = "'" if '"' in val else '"'
return quote + val + quote
def quote_if_needed(val: str) -> str:
"""Quote a string if it contains spaces and isn't already quoted."""
if is_quoted(val) or ' ' not in val:
return val
return quote(val)
def strip_quotes(val: str) -> str:
"""Strip outer quotes from a string.
Applies to both single and double quotes.
:param val: string to strip outer quotes from
:return: same string with potentially outer quotes stripped
"""
if is_quoted(val):
val = val[1:-1]
return val
def norm_fold(val: str) -> str:
"""Normalize and casefold Unicode strings for saner comparisons.
:param val: input unicode string
:return: a normalized and case-folded version of the input string
"""
import unicodedata
return unicodedata.normalize("NFC", val).casefold()
def common_prefix(m: Sequence[str]) -> str:
"""Return the longest common leading component of a list of strings.
This is a replacement for os.path.commonprefix which is deprecated in Python 3.15.
:param m: list of strings
:return: common prefix
"""
if not m:
return ""
s1 = min(m)
s2 = max(m)
for i, c in enumerate(s1):
if i >= len(s2) or c != s2[i]:
return s1[:i]
return s1