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,94 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from typing import Any, Callable, List, Optional, Type
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class EnumUtil:
|
|
6
|
+
"""枚举工具类
|
|
7
|
+
|
|
8
|
+
提供对Python枚举类型的常用操作方法,包括获取名称、值、查找等。
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
@staticmethod
|
|
12
|
+
def get_names(enum_class: Type[Enum]) -> List[str]:
|
|
13
|
+
"""获取所有枚举名称
|
|
14
|
+
|
|
15
|
+
:param enum_class: 枚举类
|
|
16
|
+
:return: 枚举名称列表
|
|
17
|
+
"""
|
|
18
|
+
return [member.name for member in enum_class]
|
|
19
|
+
|
|
20
|
+
@staticmethod
|
|
21
|
+
def get_values(enum_class: Type[Enum]) -> list:
|
|
22
|
+
"""获取所有枚举值
|
|
23
|
+
|
|
24
|
+
:param enum_class: 枚举类
|
|
25
|
+
:return: 枚举值列表
|
|
26
|
+
"""
|
|
27
|
+
return [member.value for member in enum_class]
|
|
28
|
+
|
|
29
|
+
@staticmethod
|
|
30
|
+
def get_items(enum_class: Type[Enum]) -> dict:
|
|
31
|
+
"""获取所有枚举项为字典
|
|
32
|
+
|
|
33
|
+
:param enum_class: 枚举类
|
|
34
|
+
:return: 以枚举名称为键、枚举值为值的字典
|
|
35
|
+
"""
|
|
36
|
+
return {member.name: member.value for member in enum_class}
|
|
37
|
+
|
|
38
|
+
@staticmethod
|
|
39
|
+
def contains(enum_class: Type[Enum], value: Any) -> bool:
|
|
40
|
+
"""是否包含指定值
|
|
41
|
+
|
|
42
|
+
:param enum_class: 枚举类
|
|
43
|
+
:param value: 待检查的值
|
|
44
|
+
:return: 是否包含该值
|
|
45
|
+
"""
|
|
46
|
+
try:
|
|
47
|
+
enum_class(value)
|
|
48
|
+
return True
|
|
49
|
+
except ValueError:
|
|
50
|
+
return False
|
|
51
|
+
|
|
52
|
+
@staticmethod
|
|
53
|
+
def of(enum_class: Type[Enum], name: str) -> Optional[Enum]:
|
|
54
|
+
"""根据名称获取枚举
|
|
55
|
+
|
|
56
|
+
:param enum_class: 枚举类
|
|
57
|
+
:param name: 枚举成员名称
|
|
58
|
+
:return: 对应的枚举成员,未找到返回None
|
|
59
|
+
"""
|
|
60
|
+
try:
|
|
61
|
+
return enum_class[name]
|
|
62
|
+
except KeyError:
|
|
63
|
+
return None
|
|
64
|
+
|
|
65
|
+
@staticmethod
|
|
66
|
+
def of_value(enum_class: Type[Enum], value: Any) -> Optional[Enum]:
|
|
67
|
+
"""根据值获取枚举
|
|
68
|
+
|
|
69
|
+
:param enum_class: 枚举类
|
|
70
|
+
:param value: 枚举成员的值
|
|
71
|
+
:return: 对应的枚举成员,未找到返回None
|
|
72
|
+
"""
|
|
73
|
+
try:
|
|
74
|
+
return enum_class(value)
|
|
75
|
+
except ValueError:
|
|
76
|
+
return None
|
|
77
|
+
|
|
78
|
+
@staticmethod
|
|
79
|
+
def get_by_func(
|
|
80
|
+
enum_class: Type[Enum], func: Callable[[Enum], bool], default: Optional[Enum] = None
|
|
81
|
+
) -> Optional[Enum]:
|
|
82
|
+
"""通过自定义函数查找枚举
|
|
83
|
+
|
|
84
|
+
遍历所有枚举成员,返回第一个使函数返回True的成员。
|
|
85
|
+
|
|
86
|
+
:param enum_class: 枚举类
|
|
87
|
+
:param func: 接收枚举成员并返回布尔值的函数
|
|
88
|
+
:param default: 未找到时的默认值,默认为None
|
|
89
|
+
:return: 匹配的枚举成员,未找到返回default
|
|
90
|
+
"""
|
|
91
|
+
for member in enum_class:
|
|
92
|
+
if func(member):
|
|
93
|
+
return member
|
|
94
|
+
return default
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import html
|
|
2
|
+
from urllib.parse import quote, unquote
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class EscapeUtil:
|
|
6
|
+
"""转义工具类,对应 Java cn.hutool.core.util.EscapeUtil"""
|
|
7
|
+
|
|
8
|
+
# HTML特殊字符映射
|
|
9
|
+
_HTML_ESCAPE_MAP = {
|
|
10
|
+
"&": "&",
|
|
11
|
+
"<": "<",
|
|
12
|
+
">": ">",
|
|
13
|
+
'"': """,
|
|
14
|
+
"'": "'",
|
|
15
|
+
}
|
|
16
|
+
_HTML_UNESCAPE_MAP = {v: k for k, v in _HTML_ESCAPE_MAP.items()}
|
|
17
|
+
|
|
18
|
+
@staticmethod
|
|
19
|
+
def escape_html(content: str) -> str:
|
|
20
|
+
"""HTML转义,将 & < > " ' 转义为HTML实体
|
|
21
|
+
|
|
22
|
+
:param content: 待转义的字符串
|
|
23
|
+
:return: 转义后的字符串
|
|
24
|
+
"""
|
|
25
|
+
if not content:
|
|
26
|
+
return content
|
|
27
|
+
# 先转义 & 避免二次转义
|
|
28
|
+
result = content.replace("&", "&")
|
|
29
|
+
result = result.replace("<", "<")
|
|
30
|
+
result = result.replace(">", ">")
|
|
31
|
+
result = result.replace('"', """)
|
|
32
|
+
result = result.replace("'", "'")
|
|
33
|
+
return result
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
def unescape_html(content: str) -> str:
|
|
37
|
+
"""HTML反转义,将HTML实体还原为原始字符
|
|
38
|
+
|
|
39
|
+
:param content: 待反转义的字符串
|
|
40
|
+
:return: 反转义后的字符串
|
|
41
|
+
"""
|
|
42
|
+
if not content:
|
|
43
|
+
return content
|
|
44
|
+
return html.unescape(content)
|
|
45
|
+
|
|
46
|
+
@staticmethod
|
|
47
|
+
def escape_xml(content: str) -> str:
|
|
48
|
+
"""XML转义(同HTML转义)
|
|
49
|
+
|
|
50
|
+
:param content: 待转义的字符串
|
|
51
|
+
:return: 转义后的字符串
|
|
52
|
+
"""
|
|
53
|
+
return EscapeUtil.escape_html(content)
|
|
54
|
+
|
|
55
|
+
@staticmethod
|
|
56
|
+
def unescape_xml(content: str) -> str:
|
|
57
|
+
"""XML反转义(同HTML反转义)
|
|
58
|
+
|
|
59
|
+
:param content: 待反转义的字符串
|
|
60
|
+
:return: 反转义后的字符串
|
|
61
|
+
"""
|
|
62
|
+
return EscapeUtil.unescape_html(content)
|
|
63
|
+
|
|
64
|
+
@staticmethod
|
|
65
|
+
def escape_sql(content: str) -> str:
|
|
66
|
+
"""SQL转义,将单引号转为两个单引号
|
|
67
|
+
|
|
68
|
+
:param content: 待转义的字符串
|
|
69
|
+
:return: 转义后的字符串
|
|
70
|
+
"""
|
|
71
|
+
if not content:
|
|
72
|
+
return content
|
|
73
|
+
return content.replace("'", "''")
|
|
74
|
+
|
|
75
|
+
@staticmethod
|
|
76
|
+
def escape_url(url: str, charset: str = "utf-8") -> str:
|
|
77
|
+
"""URL编码
|
|
78
|
+
|
|
79
|
+
:param url: 待编码的URL字符串
|
|
80
|
+
:param charset: 字符编码,默认utf-8
|
|
81
|
+
:return: 编码后的URL字符串
|
|
82
|
+
"""
|
|
83
|
+
if not url:
|
|
84
|
+
return url
|
|
85
|
+
return quote(url, encoding=charset, safe="")
|
|
86
|
+
|
|
87
|
+
@staticmethod
|
|
88
|
+
def unescape_url(url: str, charset: str = "utf-8") -> str:
|
|
89
|
+
"""URL解码
|
|
90
|
+
|
|
91
|
+
:param url: 待解码的URL字符串
|
|
92
|
+
:param charset: 字符编码,默认utf-8
|
|
93
|
+
:return: 解码后的URL字符串
|
|
94
|
+
"""
|
|
95
|
+
if not url:
|
|
96
|
+
return url
|
|
97
|
+
return unquote(url, encoding=charset)
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"""哈希工具类"""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class HashUtil:
|
|
5
|
+
"""哈希工具类,对应 Java cn.hutool.core.util.HashUtil
|
|
6
|
+
|
|
7
|
+
提供多种非加密哈希算法的纯Python实现。
|
|
8
|
+
所有算法结果通过 & 0xFFFFFFFF 限制为32位无符号整数。
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
@staticmethod
|
|
12
|
+
def fnv1(data: bytes) -> int:
|
|
13
|
+
"""FNV-1 哈希算法
|
|
14
|
+
|
|
15
|
+
:param data: 字节数组
|
|
16
|
+
:return: 32位哈希值
|
|
17
|
+
"""
|
|
18
|
+
if data is None:
|
|
19
|
+
return 0
|
|
20
|
+
FNV_OFFSET = 0x811C9DC5
|
|
21
|
+
FNV_PRIME = 0x01000193
|
|
22
|
+
hash_val = FNV_OFFSET
|
|
23
|
+
for b in data:
|
|
24
|
+
hash_val = (hash_val * FNV_PRIME) & 0xFFFFFFFF
|
|
25
|
+
hash_val ^= b
|
|
26
|
+
hash_val &= 0xFFFFFFFF
|
|
27
|
+
return hash_val
|
|
28
|
+
|
|
29
|
+
@staticmethod
|
|
30
|
+
def fnv1a(data: bytes) -> int:
|
|
31
|
+
"""FNV-1a 哈希算法(与FNV-1的区别在于异或和乘法的顺序相反)
|
|
32
|
+
|
|
33
|
+
:param data: 字节数组
|
|
34
|
+
:return: 32位哈希值
|
|
35
|
+
"""
|
|
36
|
+
if data is None:
|
|
37
|
+
return 0
|
|
38
|
+
FNV_OFFSET = 0x811C9DC5
|
|
39
|
+
FNV_PRIME = 0x01000193
|
|
40
|
+
hash_val = FNV_OFFSET
|
|
41
|
+
for b in data:
|
|
42
|
+
hash_val ^= b
|
|
43
|
+
hash_val = (hash_val * FNV_PRIME) & 0xFFFFFFFF
|
|
44
|
+
return hash_val
|
|
45
|
+
|
|
46
|
+
@staticmethod
|
|
47
|
+
def bkdr_hash(string: str) -> int:
|
|
48
|
+
"""BKDR 哈希算法
|
|
49
|
+
|
|
50
|
+
由Brian Kernighan与Dennis Ritchie提出,种子数为131。
|
|
51
|
+
|
|
52
|
+
:param string: 输入字符串
|
|
53
|
+
:return: 32位哈希值
|
|
54
|
+
"""
|
|
55
|
+
if string is None:
|
|
56
|
+
return 0
|
|
57
|
+
seed = 131
|
|
58
|
+
hash_val = 0
|
|
59
|
+
for ch in string:
|
|
60
|
+
hash_val = (hash_val * seed + ord(ch)) & 0xFFFFFFFF
|
|
61
|
+
return hash_val
|
|
62
|
+
|
|
63
|
+
@staticmethod
|
|
64
|
+
def ap_hash(string: str) -> int:
|
|
65
|
+
"""AP 哈希算法
|
|
66
|
+
|
|
67
|
+
由Arash Partow提出,具有很好的分布效果。
|
|
68
|
+
|
|
69
|
+
:param string: 输入字符串
|
|
70
|
+
:return: 32位哈希值
|
|
71
|
+
"""
|
|
72
|
+
if string is None:
|
|
73
|
+
return 0
|
|
74
|
+
hash_val = 0xAAAAAAAA
|
|
75
|
+
for i, ch in enumerate(string):
|
|
76
|
+
if (i & 1) == 0:
|
|
77
|
+
hash_val ^= (hash_val << 7) ^ ord(ch) ^ (hash_val >> 3)
|
|
78
|
+
else:
|
|
79
|
+
hash_val ^= ~((hash_val << 11) ^ ord(ch) ^ (hash_val >> 5))
|
|
80
|
+
hash_val &= 0xFFFFFFFF
|
|
81
|
+
return hash_val
|
|
82
|
+
|
|
83
|
+
@staticmethod
|
|
84
|
+
def djb_hash(string: str) -> int:
|
|
85
|
+
"""DJB 哈希算法
|
|
86
|
+
|
|
87
|
+
由Daniel J. Bernstein提出,使用初始值5381。
|
|
88
|
+
|
|
89
|
+
:param string: 输入字符串
|
|
90
|
+
:return: 32位哈希值
|
|
91
|
+
"""
|
|
92
|
+
if string is None:
|
|
93
|
+
return 0
|
|
94
|
+
hash_val = 5381
|
|
95
|
+
for ch in string:
|
|
96
|
+
hash_val = ((hash_val << 5) + hash_val + ord(ch)) & 0xFFFFFFFF
|
|
97
|
+
return hash_val
|
|
98
|
+
|
|
99
|
+
@staticmethod
|
|
100
|
+
def js_hash(string: str) -> int:
|
|
101
|
+
"""JS 哈希算法
|
|
102
|
+
|
|
103
|
+
Justin Sobel提出的哈希算法。
|
|
104
|
+
|
|
105
|
+
:param string: 输入字符串
|
|
106
|
+
:return: 32位哈希值
|
|
107
|
+
"""
|
|
108
|
+
if string is None:
|
|
109
|
+
return 0
|
|
110
|
+
hash_val = 0x4E67C6A7
|
|
111
|
+
for ch in string:
|
|
112
|
+
hash_val ^= (hash_val << 5) + ord(ch) + (hash_val >> 2)
|
|
113
|
+
hash_val &= 0xFFFFFFFF
|
|
114
|
+
return hash_val
|
|
115
|
+
|
|
116
|
+
@staticmethod
|
|
117
|
+
def rs_hash(string: str) -> int:
|
|
118
|
+
"""RS 哈希算法
|
|
119
|
+
|
|
120
|
+
Robert Sedgwicks提出的哈希算法。
|
|
121
|
+
|
|
122
|
+
:param string: 输入字符串
|
|
123
|
+
:return: 32位哈希值
|
|
124
|
+
"""
|
|
125
|
+
if string is None:
|
|
126
|
+
return 0
|
|
127
|
+
a = 63689
|
|
128
|
+
b = 378551
|
|
129
|
+
hash_val = 0
|
|
130
|
+
for ch in string:
|
|
131
|
+
hash_val = (hash_val * a + ord(ch)) & 0xFFFFFFFF
|
|
132
|
+
a = (a * b) & 0xFFFFFFFF
|
|
133
|
+
return hash_val
|
|
134
|
+
|
|
135
|
+
@staticmethod
|
|
136
|
+
def sdbm_hash(string: str) -> int:
|
|
137
|
+
"""SDBM 哈希算法
|
|
138
|
+
|
|
139
|
+
开源数据库SDBM使用的哈希算法。
|
|
140
|
+
|
|
141
|
+
:param string: 输入字符串
|
|
142
|
+
:return: 32位哈希值
|
|
143
|
+
"""
|
|
144
|
+
if string is None:
|
|
145
|
+
return 0
|
|
146
|
+
hash_val = 0
|
|
147
|
+
for ch in string:
|
|
148
|
+
hash_val = ord(ch) + (hash_val << 6) + (hash_val << 16) - hash_val
|
|
149
|
+
hash_val &= 0xFFFFFFFF
|
|
150
|
+
return hash_val
|
|
151
|
+
|
|
152
|
+
@staticmethod
|
|
153
|
+
def elf_hash(string: str) -> int:
|
|
154
|
+
"""ELF 哈希算法
|
|
155
|
+
|
|
156
|
+
UNIX系统ELF文件格式中使用的哈希算法。
|
|
157
|
+
|
|
158
|
+
:param string: 输入字符串
|
|
159
|
+
:return: 32位哈希值
|
|
160
|
+
"""
|
|
161
|
+
if string is None:
|
|
162
|
+
return 0
|
|
163
|
+
hash_val = 0
|
|
164
|
+
x = 0
|
|
165
|
+
for ch in string:
|
|
166
|
+
hash_val = (hash_val << 4) + ord(ch)
|
|
167
|
+
x = hash_val & 0xF0000000
|
|
168
|
+
if x != 0:
|
|
169
|
+
hash_val ^= x >> 24
|
|
170
|
+
hash_val &= ~x
|
|
171
|
+
hash_val &= 0xFFFFFFFF
|
|
172
|
+
return hash_val
|
|
173
|
+
|
|
174
|
+
@staticmethod
|
|
175
|
+
def dek_hash(string: str) -> int:
|
|
176
|
+
"""DEK 哈希算法
|
|
177
|
+
|
|
178
|
+
由Donald E. Knuth提出。
|
|
179
|
+
|
|
180
|
+
:param string: 输入字符串
|
|
181
|
+
:return: 32位哈希值
|
|
182
|
+
"""
|
|
183
|
+
if string is None:
|
|
184
|
+
return 0
|
|
185
|
+
hash_val = len(string)
|
|
186
|
+
for ch in string:
|
|
187
|
+
hash_val = ((hash_val << 5) ^ (hash_val >> 27) ^ ord(ch)) & 0xFFFFFFFF
|
|
188
|
+
return hash_val
|
|
189
|
+
|
|
190
|
+
@staticmethod
|
|
191
|
+
def bp_hash(string: str) -> int:
|
|
192
|
+
"""BP 哈希算法
|
|
193
|
+
|
|
194
|
+
:param string: 输入字符串
|
|
195
|
+
:return: 32位哈希值
|
|
196
|
+
"""
|
|
197
|
+
if string is None:
|
|
198
|
+
return 0
|
|
199
|
+
hash_val = 0
|
|
200
|
+
for ch in string:
|
|
201
|
+
hash_val = (hash_val << 7) ^ ord(ch)
|
|
202
|
+
hash_val &= 0xFFFFFFFF
|
|
203
|
+
return hash_val
|
|
204
|
+
|
|
205
|
+
@staticmethod
|
|
206
|
+
def pjw_hash(string: str) -> int:
|
|
207
|
+
"""PJW 哈希算法
|
|
208
|
+
|
|
209
|
+
Peter J. Weinberger提出的哈希算法,常用于编译器符号表。
|
|
210
|
+
|
|
211
|
+
:param string: 输入字符串
|
|
212
|
+
:return: 32位哈希值
|
|
213
|
+
"""
|
|
214
|
+
if string is None:
|
|
215
|
+
return 0
|
|
216
|
+
hash_val = 0
|
|
217
|
+
for ch in string:
|
|
218
|
+
hash_val = (hash_val << 4) + ord(ch)
|
|
219
|
+
high_bits = hash_val & 0xF0000000
|
|
220
|
+
if high_bits != 0:
|
|
221
|
+
hash_val ^= high_bits >> 24
|
|
222
|
+
hash_val &= ~high_bits
|
|
223
|
+
hash_val &= 0xFFFFFFFF
|
|
224
|
+
return hash_val
|
|
225
|
+
|
|
226
|
+
@staticmethod
|
|
227
|
+
def java_hash_code(string: str) -> int:
|
|
228
|
+
"""Java String.hashCode() 兼容实现
|
|
229
|
+
|
|
230
|
+
使用 Java 的 s*31+c 算法,结果与Java完全一致。
|
|
231
|
+
Java的hashCode使用有符号32位整数,此方法返回无符号表示。
|
|
232
|
+
|
|
233
|
+
算法: h = h * 31 + char[i]
|
|
234
|
+
|
|
235
|
+
:param string: 输入字符串
|
|
236
|
+
:return: 32位哈希值(无符号表示,范围与Java有符号int一一对应)
|
|
237
|
+
"""
|
|
238
|
+
if string is None:
|
|
239
|
+
return 0
|
|
240
|
+
h = 0
|
|
241
|
+
for ch in string:
|
|
242
|
+
h = (31 * h + ord(ch)) & 0xFFFFFFFF
|
|
243
|
+
return h
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""十六进制工具类"""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class HexUtil:
|
|
5
|
+
"""十六进制工具类,对应 Java cn.hutool.core.util.HexUtil"""
|
|
6
|
+
|
|
7
|
+
# 十六进制字符表(大写和小写)
|
|
8
|
+
_DIGITS_UPPER = "0123456789ABCDEF"
|
|
9
|
+
_DIGITS_LOWER = "0123456789abcdef"
|
|
10
|
+
|
|
11
|
+
@staticmethod
|
|
12
|
+
def encode_hex_str(data: bytes, lower_case: bool = False) -> str:
|
|
13
|
+
"""字节数组转十六进制字符串
|
|
14
|
+
|
|
15
|
+
:param data: 字节数组
|
|
16
|
+
:param lower_case: 是否使用小写,默认大写
|
|
17
|
+
:return: 十六进制字符串
|
|
18
|
+
"""
|
|
19
|
+
if data is None:
|
|
20
|
+
return ""
|
|
21
|
+
digits = HexUtil._DIGITS_LOWER if lower_case else HexUtil._DIGITS_UPPER
|
|
22
|
+
result = []
|
|
23
|
+
for b in data:
|
|
24
|
+
result.append(digits[(b >> 4) & 0x0F])
|
|
25
|
+
result.append(digits[b & 0x0F])
|
|
26
|
+
return "".join(result)
|
|
27
|
+
|
|
28
|
+
@staticmethod
|
|
29
|
+
def decode_hex(hex_str: str) -> bytes:
|
|
30
|
+
"""十六进制字符串转字节数组
|
|
31
|
+
|
|
32
|
+
:param hex_str: 十六进制字符串(允许含空格等分隔符,自动去除)
|
|
33
|
+
:return: 字节数组
|
|
34
|
+
:raises ValueError: 当输入包含非法十六进制字符时抛出
|
|
35
|
+
"""
|
|
36
|
+
if hex_str is None or len(hex_str) == 0:
|
|
37
|
+
return b""
|
|
38
|
+
# 去除常见分隔符(空格、冒号、短横线)
|
|
39
|
+
hex_str = hex_str.replace(" ", "").replace(":", "").replace("-", "")
|
|
40
|
+
length = len(hex_str)
|
|
41
|
+
if length % 2 != 0:
|
|
42
|
+
raise ValueError(f"十六进制字符串长度必须为偶数,当前长度为 {length}")
|
|
43
|
+
result = bytearray(length // 2)
|
|
44
|
+
for i in range(0, length, 2):
|
|
45
|
+
high = int(hex_str[i], 16)
|
|
46
|
+
low = int(hex_str[i + 1], 16)
|
|
47
|
+
result[i // 2] = (high << 4) | low
|
|
48
|
+
return bytes(result)
|
|
49
|
+
|
|
50
|
+
@staticmethod
|
|
51
|
+
def to_hex(number: int) -> str:
|
|
52
|
+
"""数字转十六进制字符串(不带0x前缀)
|
|
53
|
+
|
|
54
|
+
:param number: 整数
|
|
55
|
+
:return: 十六进制字符串(大写)
|
|
56
|
+
"""
|
|
57
|
+
if number == 0:
|
|
58
|
+
return "0"
|
|
59
|
+
# 处理负数:取其二进制补码表示
|
|
60
|
+
if number < 0:
|
|
61
|
+
# 转为无符号表示,取足够位数
|
|
62
|
+
number = number & 0xFFFFFFFFFFFFFFFF
|
|
63
|
+
result = []
|
|
64
|
+
while number > 0:
|
|
65
|
+
digit = number & 0x0F
|
|
66
|
+
result.append(HexUtil._DIGITS_UPPER[digit])
|
|
67
|
+
number >>= 4
|
|
68
|
+
result.reverse()
|
|
69
|
+
return "".join(result)
|
|
70
|
+
|
|
71
|
+
@staticmethod
|
|
72
|
+
def hex_to_int(hex_str: str) -> int:
|
|
73
|
+
"""十六进制字符串转int
|
|
74
|
+
|
|
75
|
+
:param hex_str: 十六进制字符串(可选0x/0X前缀)
|
|
76
|
+
:return: 对应的整数值
|
|
77
|
+
"""
|
|
78
|
+
if hex_str is None or len(hex_str) == 0:
|
|
79
|
+
raise ValueError("十六进制字符串不能为空")
|
|
80
|
+
hex_str = hex_str.strip()
|
|
81
|
+
if hex_str.startswith("0x") or hex_str.startswith("0X"):
|
|
82
|
+
hex_str = hex_str[2:]
|
|
83
|
+
return int(hex_str, 16)
|
|
84
|
+
|
|
85
|
+
@staticmethod
|
|
86
|
+
def encode_color_str(color: tuple) -> str:
|
|
87
|
+
"""RGB元组转十六进制颜色字符串
|
|
88
|
+
|
|
89
|
+
:param color: RGB元组,如 (255, 128, 0)
|
|
90
|
+
:return: 十六进制颜色字符串,如 '#FF8000'
|
|
91
|
+
"""
|
|
92
|
+
if color is None or len(color) < 3:
|
|
93
|
+
raise ValueError("颜色元组必须包含至少3个元素(R, G, B)")
|
|
94
|
+
r, g, b = color[0], color[1], color[2]
|
|
95
|
+
if not (0 <= r <= 255 and 0 <= g <= 255 and 0 <= b <= 255):
|
|
96
|
+
raise ValueError("RGB值必须在0-255范围内")
|
|
97
|
+
return f"#{r:02X}{g:02X}{b:02X}"
|
|
98
|
+
|
|
99
|
+
@staticmethod
|
|
100
|
+
def decode_color(color_str: str) -> tuple:
|
|
101
|
+
"""十六进制颜色字符串转RGB元组
|
|
102
|
+
|
|
103
|
+
:param color_str: 十六进制颜色字符串,如 '#FF8000' 或 'FF8000'
|
|
104
|
+
:return: RGB元组,如 (255, 128, 0)
|
|
105
|
+
"""
|
|
106
|
+
if color_str is None or len(color_str) == 0:
|
|
107
|
+
raise ValueError("颜色字符串不能为空")
|
|
108
|
+
color_str = color_str.strip().lstrip("#")
|
|
109
|
+
if len(color_str) == 6:
|
|
110
|
+
r = int(color_str[0:2], 16)
|
|
111
|
+
g = int(color_str[2:4], 16)
|
|
112
|
+
b = int(color_str[4:6], 16)
|
|
113
|
+
return (r, g, b)
|
|
114
|
+
elif len(color_str) == 3:
|
|
115
|
+
# 短格式如 #F80 -> #FF8800
|
|
116
|
+
r = int(color_str[0] * 2, 16)
|
|
117
|
+
g = int(color_str[1] * 2, 16)
|
|
118
|
+
b = int(color_str[2] * 2, 16)
|
|
119
|
+
return (r, g, b)
|
|
120
|
+
else:
|
|
121
|
+
raise ValueError(f"非法的颜色字符串长度:{len(color_str)},期望6位或3位")
|
|
122
|
+
|
|
123
|
+
@staticmethod
|
|
124
|
+
def format_hex(hex_str: str, delimiter: str = " ", group_size: int = 2) -> str:
|
|
125
|
+
"""格式化十六进制字符串,添加分隔符
|
|
126
|
+
|
|
127
|
+
:param hex_str: 十六进制字符串
|
|
128
|
+
:param delimiter: 分隔符,默认为空格
|
|
129
|
+
:param group_size: 每组字符数,默认为2
|
|
130
|
+
:return: 格式化后的十六进制字符串,如 '4A:3F:2B'
|
|
131
|
+
"""
|
|
132
|
+
if hex_str is None or len(hex_str) == 0:
|
|
133
|
+
return ""
|
|
134
|
+
hex_str = hex_str.replace(" ", "").replace(":", "").replace("-", "")
|
|
135
|
+
if group_size <= 0:
|
|
136
|
+
raise ValueError("group_size 必须大于 0")
|
|
137
|
+
groups = []
|
|
138
|
+
for i in range(0, len(hex_str), group_size):
|
|
139
|
+
groups.append(hex_str[i : i + group_size].upper())
|
|
140
|
+
return delimiter.join(groups)
|