gou2tool 0.2.11__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.
@@ -0,0 +1,67 @@
1
+ import os
2
+ import json
3
+
4
+
5
+ class FileUtil:
6
+
7
+ @staticmethod
8
+ def write(path, content):
9
+ """写入内容到文件(覆盖模式)"""
10
+ os.makedirs(os.path.dirname(path), exist_ok=True)
11
+ with open(path, 'w', encoding='utf-8') as file:
12
+ file.write(content)
13
+
14
+ @staticmethod
15
+ def append(path, content):
16
+ """
17
+ 追加内容到文件末尾
18
+
19
+ Args:
20
+ path (str): 文件路径
21
+ content (str): 要追加的内容
22
+ """
23
+ os.makedirs(os.path.dirname(path), exist_ok=True)
24
+ with open(path, 'a', encoding='utf-8') as file:
25
+ file.write(content)
26
+
27
+ @staticmethod
28
+ def append_line(path, content):
29
+ """
30
+ 追加一行内容到文件末尾(自动添加换行符)
31
+
32
+ Args:
33
+ path (str): 文件路径
34
+ content (str): 要追加的行内容
35
+ """
36
+ os.makedirs(os.path.dirname(path), exist_ok=True)
37
+ with open(path, 'a', encoding='utf-8') as file:
38
+ file.write(content + '\n')
39
+
40
+ @staticmethod
41
+ def read_json(path):
42
+ """
43
+ 读取JSON文件并返回解析后的数据
44
+
45
+ Args:
46
+ path (str): JSON文件路径
47
+
48
+ Returns:
49
+ dict|list: 解析后的JSON数据
50
+ """
51
+ with open(path, 'r', encoding='utf-8') as file:
52
+ return json.load(file)
53
+
54
+ @staticmethod
55
+ def write_json(path, data, ensure_ascii=False, indent=2):
56
+ """
57
+ 将数据写入JSON文件
58
+
59
+ Args:
60
+ path (str): JSON文件路径
61
+ data (dict|list): 要写入的JSON数据
62
+ ensure_ascii (bool): 是否确保ASCII编码,默认False
63
+ indent (int): 缩进空格数,默认2
64
+ """
65
+ os.makedirs(os.path.dirname(path), exist_ok=True)
66
+ with open(path, 'w', encoding='utf-8') as file:
67
+ json.dump(data, file, ensure_ascii=ensure_ascii, indent=indent)
@@ -0,0 +1,11 @@
1
+ import uuid
2
+
3
+ class IdUtil:
4
+
5
+ @staticmethod
6
+ def random_uuid():
7
+ return str(uuid.uuid4())
8
+
9
+ @staticmethod
10
+ def simple_uuid():
11
+ return str(uuid.uuid4()).replace('-', '')
@@ -0,0 +1,203 @@
1
+ import os
2
+ import re
3
+ import tempfile
4
+ import uuid
5
+ from pathlib import Path
6
+
7
+
8
+ class PathUtil:
9
+ """路径工具类"""
10
+
11
+ @staticmethod
12
+ def path(*paths):
13
+ """
14
+ 构建路径
15
+ :param paths: 路径组件
16
+ :return: 完整路径
17
+ """
18
+ # 连接路径组件
19
+ path = "/".join(paths)
20
+
21
+ # 处理特殊前缀
22
+ if path.startswith('project:'):
23
+ path = path.replace("project:", PathUtil.project_path(), 1)
24
+ elif path.startswith('goutool:'):
25
+ path = path.replace("goutool:", PathUtil.goutool_path(), 1)
26
+ elif path.startswith('gou2tool:'):
27
+ path = path.replace("gou2tool:", PathUtil.goutool_path(), 1)
28
+ elif path.startswith('system-temp:'):
29
+ path = path.replace("system-temp:", tempfile.gettempdir(), 1)
30
+ elif path.startswith('create-system-temp:'):
31
+ temp_dir = tempfile.gettempdir()
32
+ filename = path.replace("create-system-temp:", "")
33
+ path = os.path.join(temp_dir, filename)
34
+ elif path.startswith('create-system-temp-file:*'):
35
+ temp_dir = tempfile.gettempdir()
36
+ if path.startswith('create-system-temp-file:*.*'):
37
+ ext = path.replace("create-system-temp-file:*.*", ".", 1)
38
+ elif path.startswith('create-system-temp-file:*'):
39
+ ext = ".tmp"
40
+ else:
41
+ ext = ""
42
+ filename = str(uuid.uuid4()) + ext
43
+ path = os.path.join(temp_dir, filename)
44
+ elif path.startswith('vendor:'):
45
+ path = path.replace("vendor:", os.path.join(PathUtil.project_path(), "vendor"), 1)
46
+
47
+ # 规范化路径分隔符
48
+ lists = [part for part in re.split(r'([/\\]+)', path) if part]
49
+
50
+ # Linux环境下处理包含空格的路径
51
+ if os.name != 'nt': # 非Windows系统
52
+ parts = re.split(r'([\\/]+)', path)
53
+ for i, part in enumerate(parts):
54
+ if re.search(r'\s', part) and not (part.startswith('"') and part.endswith('"')):
55
+ parts[i] = f'"{part}"'
56
+ path = "".join(parts)
57
+
58
+ return "".join(lists)
59
+
60
+ @staticmethod
61
+ def raw_path(path):
62
+ """
63
+ 获取原始路径(去除引号)
64
+ :param path: 路径
65
+ :return: 原始路径
66
+ """
67
+ return path.replace('"', '')
68
+
69
+ @staticmethod
70
+ def exist(path):
71
+ """
72
+ 检查文件或目录是否存在
73
+ :param path: 路径
74
+ :return: 是否存在
75
+ """
76
+ return os.path.exists(path)
77
+
78
+ @staticmethod
79
+ def is_path(path):
80
+ """
81
+ 判断是否是有效路径格式
82
+ :param path: 路径
83
+ :return: 是否是路径
84
+ """
85
+ pattern = r'^(?:\/{2})?[a-zA-Z0-9._-]+(?:\/[a-zA-Z0-9._-]+)*$'
86
+ return bool(re.match(pattern, path))
87
+
88
+ @staticmethod
89
+ def project_path():
90
+ """
91
+ 获取应用根目录
92
+ :return: 项目路径
93
+ """
94
+ # 这里需要根据实际项目结构调整
95
+ current_dir = os.path.dirname(os.path.abspath(__file__))
96
+ project = os.path.dirname(current_dir) # 根据实际情况调整层级
97
+
98
+ project_file = os.path.join(project, "composer.json")
99
+ project_vendor = os.path.join(project, "vendor")
100
+ goutool_file = os.path.join(project, "vendor", "wl4837", "goutool", "composer.json")
101
+
102
+ if (os.path.exists(project_file) and os.path.isfile(project_file) and
103
+ os.path.exists(project_vendor) and os.path.isdir(project_vendor) and
104
+ os.path.exists(goutool_file) and os.path.isfile(goutool_file)):
105
+ return project
106
+ else:
107
+ return PathUtil.goutool_path()
108
+
109
+ @staticmethod
110
+ def goutool_path():
111
+ """
112
+ 获取框架目录
113
+ :return: 框架路径
114
+ """
115
+ path = PathUtil.parent(os.path.abspath(__file__), 6)
116
+ file_path = os.path.join(path, "setup.py")
117
+ if os.path.exists(file_path) and os.path.isfile(file_path):
118
+ return path
119
+ return False
120
+
121
+ @staticmethod
122
+ def project_composer_path():
123
+ """
124
+ 获取项目composer.json路径
125
+ :return: composer.json路径
126
+ """
127
+ project_path = PathUtil.project_path()
128
+ if project_path is False:
129
+ return False
130
+ file_path = os.path.join(project_path, "composer.json")
131
+ if os.path.exists(file_path) and os.path.isfile(file_path):
132
+ return file_path
133
+ else:
134
+ return False
135
+
136
+ @staticmethod
137
+ def project_package_path():
138
+ """
139
+ 获取项目package.json路径
140
+ :return: package.json路径
141
+ """
142
+ project_path = PathUtil.project_path()
143
+ if project_path is False:
144
+ return False
145
+ file_path = os.path.join(project_path, "package.json")
146
+ if os.path.exists(file_path) and os.path.isfile(file_path):
147
+ return file_path
148
+ else:
149
+ return False
150
+
151
+ @staticmethod
152
+ def project_env_path():
153
+ """
154
+ 获取项目.env文件路径
155
+ :return: .env文件路径
156
+ """
157
+ project_path = PathUtil.project_path()
158
+ if project_path is False:
159
+ return False
160
+ file_path = os.path.join(project_path, ".env")
161
+ if os.path.exists(file_path) and os.path.isfile(file_path):
162
+ return file_path
163
+ else:
164
+ return False
165
+
166
+ @staticmethod
167
+ def goutool_composer_path():
168
+ """
169
+ 获取框架composer.json路径
170
+ :return: composer.json路径
171
+ """
172
+ goutool_path = PathUtil.goutool_path()
173
+ if goutool_path is False:
174
+ return False
175
+ file_path = os.path.join(goutool_path, "composer.json")
176
+ if os.path.exists(file_path) and os.path.isfile(file_path):
177
+ return file_path
178
+ else:
179
+ return False
180
+
181
+ @staticmethod
182
+ def name(path):
183
+ """
184
+ 获取路径名称
185
+ :param path: 路径
186
+ :return: 路径名称
187
+ """
188
+ path = PathUtil.path(path)
189
+ return os.path.basename(path)
190
+
191
+ @staticmethod
192
+ def parent(path, level=1):
193
+ """
194
+ 获取上级路径
195
+ :param path: 路径
196
+ :param level: 上级层数
197
+ :return: 上级路径
198
+ """
199
+ path = PathUtil.path(path)
200
+ # 根据level层数逐级获取上级目录
201
+ for _ in range(level):
202
+ path = os.path.dirname(path)
203
+ return path
@@ -0,0 +1,25 @@
1
+ import re
2
+
3
+ class PhoneUtil:
4
+
5
+ @staticmethod
6
+ def is_phone(value):
7
+ if not value:
8
+ return False
9
+ return PhoneUtil.is_mobile(value) or PhoneUtil.is_tel(value)
10
+
11
+ @staticmethod
12
+ def is_mobile(value):
13
+ if not value:
14
+ return False
15
+ return bool(re.match(r'^1[3-9]\d{9}$', value))
16
+
17
+ @staticmethod
18
+ def is_tel(value):
19
+ if not value:
20
+ return False
21
+ return bool(re.match(r'^(0\d{2,3}[- ]?)?\d{7,8}(-\d{1,6})?$', value))
22
+
23
+ @staticmethod
24
+ def hide_between(phone):
25
+ return phone[0:3] + '****' + phone[-4:]
@@ -0,0 +1,208 @@
1
+ import json
2
+
3
+ class SQLUtil:
4
+ """SQL语句生成工具类"""
5
+
6
+ @staticmethod
7
+ def escape_string(val):
8
+ """
9
+ 转义SQL字符串中的特殊字符
10
+
11
+ Args:
12
+ val: 要转义的字符串
13
+
14
+ Returns:
15
+ 转义后的字符串
16
+ """
17
+ if isinstance(val, str):
18
+ # 转义单引号
19
+ return val.replace("'", "''")
20
+ return val
21
+
22
+ @staticmethod
23
+ def format_value(val):
24
+ """
25
+ 格式化值为SQL字符串
26
+
27
+ Args:
28
+ val: 要格式化的值
29
+
30
+ Returns:
31
+ 格式化后的SQL值字符串
32
+ """
33
+ if val is None:
34
+ return "NULL"
35
+ elif isinstance(val, str):
36
+ # 转义字符串并加引号
37
+ escaped_val = SQLUtil.escape_string(val)
38
+ return f"'{escaped_val}'"
39
+ elif isinstance(val, (list, tuple)):
40
+ # 数组转为逗号分隔的字符串
41
+ escaped_val = SQLUtil.escape_string(','.join(map(str, val)))
42
+ return f"'{escaped_val}'"
43
+ elif isinstance(val, dict):
44
+ # 字典转为JSON字符串
45
+ escaped_val = SQLUtil.escape_string(json.dumps(val, ensure_ascii=False))
46
+ return f"'{escaped_val}'"
47
+ else:
48
+ return str(val)
49
+
50
+ @staticmethod
51
+ def insert(table: str, data: dict, returning: str = None) -> str:
52
+ """
53
+ 生成INSERT SQL语句
54
+
55
+ Args:
56
+ table: 表名
57
+ data: 要插入的数据字典 {列名: 值}
58
+ returning: 返回指定列的值(可选)
59
+
60
+ Returns:
61
+ INSERT SQL语句
62
+ """
63
+ columns = ', '.join(data.keys())
64
+
65
+ # 直接使用值而不是占位符
66
+ values = []
67
+ for val in data.values():
68
+ values.append(SQLUtil.format_value(val))
69
+
70
+ placeholders = ', '.join(values)
71
+ sql = f"INSERT INTO {table} ({columns}) VALUES ({placeholders})"
72
+
73
+ if returning:
74
+ sql += f" RETURNING {returning}"
75
+
76
+ return sql
77
+
78
+ @staticmethod
79
+ def batch_insert(table: str, data_list: list) -> str:
80
+ """
81
+ 生成批量INSERT SQL语句
82
+
83
+ Args:
84
+ table: 表名
85
+ data_list: 要插入的数据列表 [{列名: 值}, ...]
86
+
87
+ Returns:
88
+ 批量INSERT SQL语句
89
+ """
90
+ if not data_list:
91
+ return ""
92
+
93
+ columns = ', '.join(data_list[0].keys())
94
+ sql = f"INSERT INTO {table} ({columns}) VALUES "
95
+
96
+ # 构建所有值的列表
97
+ value_groups = []
98
+ for data in data_list:
99
+ values = []
100
+ for val in data.values():
101
+ values.append(SQLUtil.format_value(val))
102
+ value_groups.append(f"({', '.join(values)})")
103
+
104
+ sql += ', '.join(value_groups)
105
+ return sql
106
+
107
+ @staticmethod
108
+ def update(table: str, data: dict, where: dict = None, where_clause: str = None) -> str:
109
+ """
110
+ 生成UPDATE SQL语句
111
+
112
+ Args:
113
+ table: 表名
114
+ data: 要更新的数据字典 {列名: 值}
115
+ where: WHERE条件字典 {列名: 值}
116
+ where_clause: 自定义WHERE子句(可选)
117
+
118
+ Returns:
119
+ UPDATE SQL语句
120
+ """
121
+ if not data:
122
+ raise ValueError("更新数据不能为空")
123
+
124
+ # 直接使用值而不是占位符
125
+ set_parts = []
126
+ for col, val in data.items():
127
+ formatted_val = SQLUtil.format_value(val)
128
+ set_parts.append(f"`{col}` = {formatted_val}")
129
+
130
+ set_clause = ', '.join(set_parts)
131
+ sql = f"UPDATE `{table}` SET {set_clause}"
132
+
133
+ # 处理WHERE条件
134
+ if where_clause:
135
+ sql += f" WHERE {where_clause}"
136
+ elif where:
137
+ where_parts = []
138
+ for col, val in where.items():
139
+ if val is None:
140
+ where_parts.append(f"`{col}` IS NULL")
141
+ elif isinstance(val, dict):
142
+ # 支持操作符字典 {"=": 1, ">": 5, "LIKE": "%test%", "IN": [1,2,3]}
143
+ for op, op_val in val.items():
144
+ if op.upper() == "IN" and isinstance(op_val, (list, tuple)):
145
+ in_vals = [SQLUtil.format_value(v) for v in op_val]
146
+ where_parts.append(f"`{col}` IN ({', '.join(in_vals)})")
147
+ if op.upper() == "NOT IN" and isinstance(op_val, (list, tuple)):
148
+ in_vals = [SQLUtil.format_value(v) for v in op_val]
149
+ where_parts.append(f"`{col}` NOT IN ({', '.join(in_vals)})")
150
+ elif op.upper() in ["LIKE", "=", "!=", ">", "<", ">=", "<="]:
151
+ formatted_val = SQLUtil.format_value(op_val)
152
+ where_parts.append(f"`{col}` {op.upper()} {formatted_val}")
153
+ else:
154
+ formatted_val = SQLUtil.format_value(op_val)
155
+ where_parts.append(f"`{col}` {op} {formatted_val}")
156
+ else:
157
+ formatted_val = SQLUtil.format_value(val)
158
+ where_parts.append(f"`{col}` = {formatted_val}")
159
+ if where_parts:
160
+ sql += " WHERE " + " AND ".join(where_parts)
161
+
162
+ return sql
163
+
164
+ @staticmethod
165
+ def delete(table: str, where: dict = None, where_clause: str = None) -> str:
166
+ """
167
+ 生成DELETE SQL语句
168
+
169
+ Args:
170
+ table: 表名
171
+ where: WHERE条件字典 {列名: 值}
172
+ where_clause: 自定义WHERE子句(可选)
173
+
174
+ Returns:
175
+ DELETE SQL语句
176
+ """
177
+ sql = f"DELETE FROM {table}"
178
+
179
+ # 处理WHERE条件
180
+ if where_clause:
181
+ sql += f" WHERE {where_clause}"
182
+ elif where:
183
+ where_parts = []
184
+ for col, val in where.items():
185
+ if val is None:
186
+ where_parts.append(f"{col} IS NULL")
187
+ elif isinstance(val, dict):
188
+ # 支持操作符字典 {"=": 1, ">": 5, "LIKE": "%test%", "IN": [1,2,3]}
189
+ for op, op_val in val.items():
190
+ if op.upper() == "IN" and isinstance(op_val, (list, tuple)):
191
+ in_vals = [SQLUtil.format_value(v) for v in op_val]
192
+ where_parts.append(f"{col} IN ({', '.join(in_vals)})")
193
+ elif op.upper() in ["LIKE", "=", "!=", ">", "<", ">=", "<="]:
194
+ formatted_val = SQLUtil.format_value(op_val)
195
+ where_parts.append(f"{col} {op.upper()} {formatted_val}")
196
+ else:
197
+ formatted_val = SQLUtil.format_value(op_val)
198
+ where_parts.append(f"{col} {op} {formatted_val}")
199
+ else:
200
+ formatted_val = SQLUtil.format_value(val)
201
+ where_parts.append(f"{col} = {formatted_val}")
202
+ if where_parts:
203
+ sql += " WHERE " + " AND ".join(where_parts)
204
+ else:
205
+ # 防止意外删除所有数据
206
+ raise ValueError("删除操作必须提供WHERE条件")
207
+
208
+ return sql
@@ -0,0 +1,51 @@
1
+ import json
2
+
3
+ class StrUtil:
4
+
5
+ @staticmethod
6
+ def calculate_similarity(str1, str2):
7
+ """
8
+ 计算两个字符串的相似度,返回百分比
9
+
10
+ Args:
11
+ str1 (str): 第一个字符串
12
+ str2 (str): 第二个字符串
13
+
14
+ Returns:
15
+ float: 相似度百分比 (0-100)
16
+ """
17
+ if not str1 and not str2:
18
+ return 100.0
19
+ if not str1 or not str2:
20
+ return 0.0
21
+
22
+ # 转换为小写进行比较
23
+ s1, s2 = str1.lower(), str2.lower()
24
+ m, n = len(s1), len(s2)
25
+
26
+ # 创建DP表并计算编辑距离
27
+ dp = [[0] * (n + 1) for _ in range(m + 1)]
28
+
29
+ # 初始化边界条件
30
+ for i in range(m + 1):
31
+ dp[i][0] = i
32
+ for j in range(n + 1):
33
+ dp[0][j] = j
34
+
35
+ # 填充DP表
36
+ for i in range(1, m + 1):
37
+ for j in range(1, n + 1):
38
+ if s1[i - 1] == s2[j - 1]:
39
+ dp[i][j] = dp[i - 1][j - 1]
40
+ else:
41
+ dp[i][j] = min(
42
+ dp[i - 1][j] + 1, # 删除
43
+ dp[i][j - 1] + 1, # 插入
44
+ dp[i - 1][j - 1] + 1 # 替换
45
+ )
46
+
47
+ # 计算相似度百分比
48
+ distance = dp[m][n]
49
+ max_len = max(len(s1), len(s2))
50
+ similarity = (1 - distance / max_len) * 100
51
+ return round(similarity, 2)
File without changes