hutool-python 1.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.
- hutool/__init__.py +174 -0
- hutool/cache/__init__.py +7 -0
- hutool/cache/cache_util.py +47 -0
- hutool/cache/fifo_cache.py +87 -0
- hutool/cache/lfu_cache.py +129 -0
- hutool/cache/lru_cache.py +93 -0
- hutool/cache/timed_cache.py +115 -0
- hutool/captcha/__init__.py +3 -0
- hutool/captcha/captcha_util.py +215 -0
- hutool/core/__init__.py +23 -0
- hutool/core/_base.py +61 -0
- hutool/core/bean.py +214 -0
- hutool/core/codec.py +111 -0
- hutool/core/coll.py +635 -0
- hutool/core/date.py +1024 -0
- hutool/core/exceptions.py +66 -0
- hutool/core/io/__init__.py +0 -0
- hutool/core/io/data_size_util.py +79 -0
- hutool/core/io/file_name_util.py +111 -0
- hutool/core/io/file_util.py +650 -0
- hutool/core/io/io_util.py +133 -0
- hutool/core/io/path_util.py +247 -0
- hutool/core/io/resource_util.py +137 -0
- hutool/core/map.py +933 -0
- hutool/core/math_util.py +105 -0
- hutool/core/net.py +288 -0
- hutool/core/text/__init__.py +0 -0
- hutool/core/text/csv_util.py +54 -0
- hutool/core/text/str_builder.py +224 -0
- hutool/core/text/unicode_util.py +58 -0
- hutool/core/tree.py +242 -0
- hutool/core/util/__init__.py +63 -0
- hutool/core/util/array_util.py +503 -0
- hutool/core/util/boolean_util.py +124 -0
- hutool/core/util/charset_util.py +60 -0
- hutool/core/util/class_util.py +136 -0
- hutool/core/util/coordinate_util.py +186 -0
- hutool/core/util/credit_code_util.py +110 -0
- hutool/core/util/desensitized_util.py +194 -0
- hutool/core/util/enum_util.py +94 -0
- hutool/core/util/escape_util.py +97 -0
- hutool/core/util/hash_util.py +243 -0
- hutool/core/util/hex_util.py +140 -0
- hutool/core/util/id_util.py +147 -0
- hutool/core/util/idcard_util.py +300 -0
- hutool/core/util/number_util.py +720 -0
- hutool/core/util/object_util.py +294 -0
- hutool/core/util/page_util.py +61 -0
- hutool/core/util/phone_util.py +140 -0
- hutool/core/util/random_util.py +112 -0
- hutool/core/util/re_util.py +231 -0
- hutool/core/util/reflect_util.py +135 -0
- hutool/core/util/runtime_util.py +89 -0
- hutool/core/util/str_util.py +2320 -0
- hutool/core/util/system_util.py +62 -0
- hutool/core/util/url_util.py +232 -0
- hutool/core/util/version_util.py +41 -0
- hutool/core/util/xml_util.py +158 -0
- hutool/core/util/zip_util.py +126 -0
- hutool/cron/__init__.py +4 -0
- hutool/cron/cron_pattern.py +123 -0
- hutool/cron/cron_util.py +115 -0
- hutool/crypto/__init__.py +5 -0
- hutool/crypto/digest_util.py +167 -0
- hutool/crypto/secure_util.py +311 -0
- hutool/crypto/sign_util.py +74 -0
- hutool/dfa/__init__.py +3 -0
- hutool/dfa/sensitive_util.py +114 -0
- hutool/extra/__init__.py +6 -0
- hutool/extra/emoji_util.py +90 -0
- hutool/extra/pinyin_util.py +44 -0
- hutool/extra/qr_code_util.py +58 -0
- hutool/extra/template_util.py +41 -0
- hutool/http/__init__.py +6 -0
- hutool/http/html_util.py +88 -0
- hutool/http/http_request.py +188 -0
- hutool/http/http_response.py +139 -0
- hutool/http/http_util.py +237 -0
- hutool/json_util.py +251 -0
- hutool/jwt_util.py +57 -0
- hutool/setting/__init__.py +5 -0
- hutool/setting/props_util.py +79 -0
- hutool/setting/setting_util.py +80 -0
- hutool/setting/yaml_util.py +45 -0
- hutool_python-1.0.0.dist-info/LICENSE +127 -0
- hutool_python-1.0.0.dist-info/METADATA +438 -0
- hutool_python-1.0.0.dist-info/RECORD +89 -0
- hutool_python-1.0.0.dist-info/WHEEL +5 -0
- hutool_python-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from typing import List
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class UnicodeUtil:
|
|
6
|
+
"""Unicode工具类"""
|
|
7
|
+
|
|
8
|
+
@staticmethod
|
|
9
|
+
def to_unicode(string: str) -> str:
|
|
10
|
+
"""字符串转Unicode,如 "中文" -> "\\u4e2d\\u6587"
|
|
11
|
+
|
|
12
|
+
:param string: 原始字符串
|
|
13
|
+
:return: Unicode转义后的字符串
|
|
14
|
+
"""
|
|
15
|
+
return string.encode("unicode_escape").decode("ascii")
|
|
16
|
+
|
|
17
|
+
@staticmethod
|
|
18
|
+
def from_unicode(unicode_str: str) -> str:
|
|
19
|
+
"""Unicode转字符串,如 "\\u4e2d\\u6587" -> "中文"
|
|
20
|
+
|
|
21
|
+
:param unicode_str: Unicode转义字符串
|
|
22
|
+
:return: 解码后的原始字符串
|
|
23
|
+
"""
|
|
24
|
+
return unicode_str.encode("ascii").decode("unicode_escape")
|
|
25
|
+
|
|
26
|
+
@staticmethod
|
|
27
|
+
def escape(content: str) -> str:
|
|
28
|
+
"""转义非ASCII字符为Unicode
|
|
29
|
+
|
|
30
|
+
将字符串中所有非ASCII字符转换为 \\uXXXX 格式的Unicode转义序列,
|
|
31
|
+
ASCII字符保持不变。
|
|
32
|
+
|
|
33
|
+
:param content: 原始字符串
|
|
34
|
+
:return: 转义后的字符串
|
|
35
|
+
"""
|
|
36
|
+
result: List[str] = []
|
|
37
|
+
for ch in content:
|
|
38
|
+
if ord(ch) > 127:
|
|
39
|
+
result.append(f"\\u{ord(ch):04x}")
|
|
40
|
+
else:
|
|
41
|
+
result.append(ch)
|
|
42
|
+
return "".join(result)
|
|
43
|
+
|
|
44
|
+
@staticmethod
|
|
45
|
+
def unescape(content: str) -> str:
|
|
46
|
+
"""反转义Unicode字符
|
|
47
|
+
|
|
48
|
+
将字符串中的 \\uXXXX 格式的Unicode转义序列还原为实际字符,
|
|
49
|
+
同时支持 \\uXXXXX 等五位及以上的Unicode码点。
|
|
50
|
+
|
|
51
|
+
:param content: 包含Unicode转义序列的字符串
|
|
52
|
+
:return: 还原后的原始字符串
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def _replace(match: re.Match) -> str:
|
|
56
|
+
return chr(int(match.group(1), 16))
|
|
57
|
+
|
|
58
|
+
return re.sub(r"\\u([0-9a-fA-F]{4,})", _replace, content)
|
hutool/core/tree.py
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
from collections import deque
|
|
2
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class TreeNode:
|
|
6
|
+
"""树节点
|
|
7
|
+
|
|
8
|
+
用于表示树结构中的单个节点,包含节点标识、父节点标识、
|
|
9
|
+
名称、权重、子节点列表以及扩展属性。
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
id: Any = None,
|
|
15
|
+
parent_id: Any = None,
|
|
16
|
+
name: str = "",
|
|
17
|
+
weight: int = 0,
|
|
18
|
+
):
|
|
19
|
+
"""初始化树节点
|
|
20
|
+
|
|
21
|
+
:param id: 节点唯一标识
|
|
22
|
+
:param parent_id: 父节点标识,根节点通常为 None 或特定根标识
|
|
23
|
+
:param name: 节点名称
|
|
24
|
+
:param weight: 节点权重,用于排序
|
|
25
|
+
"""
|
|
26
|
+
self.id = id
|
|
27
|
+
self.parent_id = parent_id
|
|
28
|
+
self.name = name
|
|
29
|
+
self.weight = weight
|
|
30
|
+
self.children: List[TreeNode] = []
|
|
31
|
+
self.extra: Dict[str, Any] = {}
|
|
32
|
+
|
|
33
|
+
def __repr__(self) -> str:
|
|
34
|
+
return (
|
|
35
|
+
f"TreeNode(id={self.id!r}, parent_id={self.parent_id!r}, "
|
|
36
|
+
f"name={self.name!r}, weight={self.weight}, "
|
|
37
|
+
f"children_count={len(self.children)})"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def to_dict(self) -> dict:
|
|
41
|
+
"""将节点及其子树转为字典
|
|
42
|
+
|
|
43
|
+
:return: 包含节点信息和子节点列表的字典
|
|
44
|
+
"""
|
|
45
|
+
result = {
|
|
46
|
+
"id": self.id,
|
|
47
|
+
"parentId": self.parent_id,
|
|
48
|
+
"name": self.name,
|
|
49
|
+
"weight": self.weight,
|
|
50
|
+
"children": [child.to_dict() for child in self.children],
|
|
51
|
+
}
|
|
52
|
+
if self.extra:
|
|
53
|
+
result.update(self.extra)
|
|
54
|
+
return result
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class TreeUtil:
|
|
58
|
+
"""树工具类
|
|
59
|
+
|
|
60
|
+
提供从平铺列表构建树、遍历、查找、统计等常用操作。
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
@staticmethod
|
|
64
|
+
def build(
|
|
65
|
+
list_data: List[dict],
|
|
66
|
+
root_id: Any = None,
|
|
67
|
+
id_field: str = "id",
|
|
68
|
+
parent_field: str = "parentId",
|
|
69
|
+
children_field: str = "children",
|
|
70
|
+
name_field: str = "name",
|
|
71
|
+
weight_field: str = "weight",
|
|
72
|
+
) -> List[TreeNode]:
|
|
73
|
+
"""从平铺列表构建树
|
|
74
|
+
|
|
75
|
+
将包含 id 和 parentId 的平铺字典列表转换为树形结构。
|
|
76
|
+
|
|
77
|
+
:param list_data: 平铺的字典列表
|
|
78
|
+
:param root_id: 根节点的 parent_id 值,默认为 None
|
|
79
|
+
:param id_field: 节点ID字段名,默认 "id"
|
|
80
|
+
:param parent_field: 父节点ID字段名,默认 "parentId"
|
|
81
|
+
:param children_field: 子节点列表字段名,默认 "children"
|
|
82
|
+
:param name_field: 节点名称字段名,默认 "name"
|
|
83
|
+
:param weight_field: 权重字段名,默认 "weight"
|
|
84
|
+
:return: 根节点列表(可能有多个顶级节点)
|
|
85
|
+
"""
|
|
86
|
+
# 构建 id -> TreeNode 的映射
|
|
87
|
+
node_map: Dict[Any, TreeNode] = {}
|
|
88
|
+
for item in list_data:
|
|
89
|
+
node_id = item.get(id_field)
|
|
90
|
+
node = TreeNode(
|
|
91
|
+
id=node_id,
|
|
92
|
+
parent_id=item.get(parent_field),
|
|
93
|
+
name=str(item.get(name_field, "")),
|
|
94
|
+
weight=int(item.get(weight_field, 0)),
|
|
95
|
+
)
|
|
96
|
+
# 将未识别的字段存入 extra
|
|
97
|
+
known_fields = {id_field, parent_field, children_field, name_field, weight_field}
|
|
98
|
+
for key, value in item.items():
|
|
99
|
+
if key not in known_fields:
|
|
100
|
+
node.extra[key] = value
|
|
101
|
+
node_map[node_id] = node
|
|
102
|
+
|
|
103
|
+
# 组装父子关系
|
|
104
|
+
roots: List[TreeNode] = []
|
|
105
|
+
for item in list_data:
|
|
106
|
+
node_id = item.get(id_field)
|
|
107
|
+
parent_id = item.get(parent_field)
|
|
108
|
+
node = node_map[node_id]
|
|
109
|
+
if parent_id == root_id or parent_id not in node_map:
|
|
110
|
+
roots.append(node)
|
|
111
|
+
else:
|
|
112
|
+
parent = node_map.get(parent_id)
|
|
113
|
+
if parent is not None:
|
|
114
|
+
parent.children.append(node)
|
|
115
|
+
|
|
116
|
+
# 按权重排序子节点
|
|
117
|
+
def _sort_children(nodes: List[TreeNode]) -> None:
|
|
118
|
+
nodes.sort(key=lambda n: n.weight)
|
|
119
|
+
for child in nodes:
|
|
120
|
+
_sort_children(child.children)
|
|
121
|
+
|
|
122
|
+
_sort_children(roots)
|
|
123
|
+
return roots
|
|
124
|
+
|
|
125
|
+
@staticmethod
|
|
126
|
+
def get_node_id(tree_nodes: List[TreeNode], node_id: Any) -> Optional[TreeNode]:
|
|
127
|
+
"""根据ID查找节点
|
|
128
|
+
|
|
129
|
+
:param tree_nodes: 树节点列表
|
|
130
|
+
:param node_id: 要查找的节点ID
|
|
131
|
+
:return: 匹配的节点,未找到返回 None
|
|
132
|
+
"""
|
|
133
|
+
queue = deque(tree_nodes)
|
|
134
|
+
while queue:
|
|
135
|
+
node = queue.popleft()
|
|
136
|
+
if node.id == node_id:
|
|
137
|
+
return node
|
|
138
|
+
queue.extend(node.children)
|
|
139
|
+
return None
|
|
140
|
+
|
|
141
|
+
@staticmethod
|
|
142
|
+
def to_list(tree_nodes: List[TreeNode]) -> List[dict]:
|
|
143
|
+
"""树转平铺列表
|
|
144
|
+
|
|
145
|
+
将树形结构展平为字典列表,广度优先遍历。
|
|
146
|
+
|
|
147
|
+
:param tree_nodes: 根节点列表
|
|
148
|
+
:return: 平铺的字典列表
|
|
149
|
+
"""
|
|
150
|
+
result: List[dict] = []
|
|
151
|
+
queue = deque(tree_nodes)
|
|
152
|
+
while queue:
|
|
153
|
+
node = queue.popleft()
|
|
154
|
+
result.append(node.to_dict())
|
|
155
|
+
queue.extend(node.children)
|
|
156
|
+
return result
|
|
157
|
+
|
|
158
|
+
@staticmethod
|
|
159
|
+
def foreach(
|
|
160
|
+
tree_nodes: List[TreeNode],
|
|
161
|
+
consumer: Callable[[TreeNode], None],
|
|
162
|
+
) -> None:
|
|
163
|
+
"""广度优先遍历(BFS)
|
|
164
|
+
|
|
165
|
+
对树中每个节点执行 consumer 回调。
|
|
166
|
+
|
|
167
|
+
:param tree_nodes: 根节点列表
|
|
168
|
+
:param consumer: 遍历回调函数
|
|
169
|
+
"""
|
|
170
|
+
queue = deque(tree_nodes)
|
|
171
|
+
while queue:
|
|
172
|
+
node = queue.popleft()
|
|
173
|
+
consumer(node)
|
|
174
|
+
queue.extend(node.children)
|
|
175
|
+
|
|
176
|
+
@staticmethod
|
|
177
|
+
def foreach_df(
|
|
178
|
+
tree_nodes: List[TreeNode],
|
|
179
|
+
consumer: Callable[[TreeNode], None],
|
|
180
|
+
) -> None:
|
|
181
|
+
"""深度优先遍历(DFS)
|
|
182
|
+
|
|
183
|
+
对树中每个节点执行 consumer 回调,使用栈实现非递归遍历。
|
|
184
|
+
|
|
185
|
+
:param tree_nodes: 根节点列表
|
|
186
|
+
:param consumer: 遍历回调函数
|
|
187
|
+
"""
|
|
188
|
+
stack = list(reversed(tree_nodes))
|
|
189
|
+
while stack:
|
|
190
|
+
node = stack.pop()
|
|
191
|
+
consumer(node)
|
|
192
|
+
# 反向压栈以保证从左到右的遍历顺序
|
|
193
|
+
stack.extend(reversed(node.children))
|
|
194
|
+
|
|
195
|
+
@staticmethod
|
|
196
|
+
def to_map(tree_nodes: List[TreeNode]) -> Dict[Any, TreeNode]:
|
|
197
|
+
"""树转ID到节点的映射
|
|
198
|
+
|
|
199
|
+
:param tree_nodes: 根节点列表
|
|
200
|
+
:return: 以节点ID为键、节点对象为值的字典
|
|
201
|
+
"""
|
|
202
|
+
result: Dict[Any, TreeNode] = {}
|
|
203
|
+
queue = deque(tree_nodes)
|
|
204
|
+
while queue:
|
|
205
|
+
node = queue.popleft()
|
|
206
|
+
result[node.id] = node
|
|
207
|
+
queue.extend(node.children)
|
|
208
|
+
return result
|
|
209
|
+
|
|
210
|
+
@staticmethod
|
|
211
|
+
def count(tree_nodes: List[TreeNode]) -> int:
|
|
212
|
+
"""统计节点总数
|
|
213
|
+
|
|
214
|
+
:param tree_nodes: 根节点列表
|
|
215
|
+
:return: 树中所有节点的数量
|
|
216
|
+
"""
|
|
217
|
+
total = 0
|
|
218
|
+
queue = deque(tree_nodes)
|
|
219
|
+
while queue:
|
|
220
|
+
node = queue.popleft()
|
|
221
|
+
total += 1
|
|
222
|
+
queue.extend(node.children)
|
|
223
|
+
return total
|
|
224
|
+
|
|
225
|
+
@staticmethod
|
|
226
|
+
def get_leaf_nodes(tree_nodes: List[TreeNode]) -> List[TreeNode]:
|
|
227
|
+
"""获取所有叶子节点
|
|
228
|
+
|
|
229
|
+
叶子节点是指没有子节点的节点。
|
|
230
|
+
|
|
231
|
+
:param tree_nodes: 根节点列表
|
|
232
|
+
:return: 叶子节点列表
|
|
233
|
+
"""
|
|
234
|
+
leaves: List[TreeNode] = []
|
|
235
|
+
queue = deque(tree_nodes)
|
|
236
|
+
while queue:
|
|
237
|
+
node = queue.popleft()
|
|
238
|
+
if not node.children:
|
|
239
|
+
leaves.append(node)
|
|
240
|
+
else:
|
|
241
|
+
queue.extend(node.children)
|
|
242
|
+
return leaves
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Core util 工具类导出。"""
|
|
2
|
+
|
|
3
|
+
from .array_util import ArrayUtil
|
|
4
|
+
from .boolean_util import BooleanUtil
|
|
5
|
+
from .charset_util import CharsetUtil
|
|
6
|
+
from .class_util import ClassUtil
|
|
7
|
+
from .coordinate_util import CoordinateUtil
|
|
8
|
+
from .credit_code_util import CreditCodeUtil
|
|
9
|
+
from .desensitized_util import DesensitizedUtil
|
|
10
|
+
from .enum_util import EnumUtil
|
|
11
|
+
from .escape_util import EscapeUtil
|
|
12
|
+
from .hash_util import HashUtil
|
|
13
|
+
from .hex_util import HexUtil
|
|
14
|
+
from .id_util import IdUtil
|
|
15
|
+
from .idcard_util import IdcardUtil
|
|
16
|
+
from .number_util import NumberUtil
|
|
17
|
+
from .object_util import ObjectUtil
|
|
18
|
+
from .page_util import PageUtil
|
|
19
|
+
from .phone_util import PhoneUtil
|
|
20
|
+
from .random_util import RandomUtil
|
|
21
|
+
from .re_util import ReUtil
|
|
22
|
+
from .reflect_util import ReflectUtil
|
|
23
|
+
from .runtime_util import RuntimeUtil
|
|
24
|
+
from .str_util import CharPool, CharSequenceUtil, CharUtil, StrPool, StrUtil
|
|
25
|
+
from .system_util import SystemUtil
|
|
26
|
+
from .url_util import URLUtil
|
|
27
|
+
from .version_util import VersionUtil
|
|
28
|
+
from .xml_util import XmlUtil
|
|
29
|
+
from .zip_util import ZipUtil
|
|
30
|
+
|
|
31
|
+
__all__ = [
|
|
32
|
+
"ArrayUtil",
|
|
33
|
+
"BooleanUtil",
|
|
34
|
+
"CharPool",
|
|
35
|
+
"CharSequenceUtil",
|
|
36
|
+
"CharUtil",
|
|
37
|
+
"CharsetUtil",
|
|
38
|
+
"ClassUtil",
|
|
39
|
+
"CoordinateUtil",
|
|
40
|
+
"CreditCodeUtil",
|
|
41
|
+
"DesensitizedUtil",
|
|
42
|
+
"EnumUtil",
|
|
43
|
+
"EscapeUtil",
|
|
44
|
+
"HashUtil",
|
|
45
|
+
"HexUtil",
|
|
46
|
+
"IdUtil",
|
|
47
|
+
"IdcardUtil",
|
|
48
|
+
"NumberUtil",
|
|
49
|
+
"ObjectUtil",
|
|
50
|
+
"PageUtil",
|
|
51
|
+
"PhoneUtil",
|
|
52
|
+
"RandomUtil",
|
|
53
|
+
"ReUtil",
|
|
54
|
+
"ReflectUtil",
|
|
55
|
+
"RuntimeUtil",
|
|
56
|
+
"StrPool",
|
|
57
|
+
"StrUtil",
|
|
58
|
+
"SystemUtil",
|
|
59
|
+
"URLUtil",
|
|
60
|
+
"VersionUtil",
|
|
61
|
+
"XmlUtil",
|
|
62
|
+
"ZipUtil",
|
|
63
|
+
]
|