re-common 10.0.37__py3-none-any.whl → 10.0.39__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.
Files changed (217) hide show
  1. re_common/baselibrary/__init__.py +4 -4
  2. re_common/baselibrary/baseabs/__init__.py +6 -6
  3. re_common/baselibrary/baseabs/baseabs.py +26 -26
  4. re_common/baselibrary/database/mbuilder.py +132 -132
  5. re_common/baselibrary/database/moudle.py +93 -93
  6. re_common/baselibrary/database/msqlite3.py +194 -194
  7. re_common/baselibrary/database/mysql.py +169 -169
  8. re_common/baselibrary/database/sql_factory.py +26 -26
  9. re_common/baselibrary/mthread/MThreadingRun.py +486 -486
  10. re_common/baselibrary/mthread/MThreadingRunEvent.py +349 -349
  11. re_common/baselibrary/mthread/__init__.py +2 -2
  12. re_common/baselibrary/mthread/mythreading.py +695 -695
  13. re_common/baselibrary/pakge_other/socks.py +404 -404
  14. re_common/baselibrary/readconfig/config_factory.py +18 -18
  15. re_common/baselibrary/readconfig/ini_config.py +317 -317
  16. re_common/baselibrary/readconfig/toml_config.py +49 -49
  17. re_common/baselibrary/temporary/envdata.py +36 -36
  18. re_common/baselibrary/tools/all_requests/aiohttp_request.py +118 -118
  19. re_common/baselibrary/tools/all_requests/httpx_requet.py +102 -102
  20. re_common/baselibrary/tools/all_requests/mrequest.py +412 -412
  21. re_common/baselibrary/tools/all_requests/requests_request.py +81 -81
  22. re_common/baselibrary/tools/batch_compre/bijiao_batch.py +31 -31
  23. re_common/baselibrary/tools/contrast_db3.py +123 -123
  24. re_common/baselibrary/tools/copy_file.py +39 -39
  25. re_common/baselibrary/tools/db3_2_sizedb3.py +102 -102
  26. re_common/baselibrary/tools/foreachgz.py +39 -39
  27. re_common/baselibrary/tools/get_attr.py +10 -10
  28. re_common/baselibrary/tools/image_to_pdf.py +61 -61
  29. re_common/baselibrary/tools/java_code_deal.py +139 -139
  30. re_common/baselibrary/tools/javacode.py +79 -79
  31. re_common/baselibrary/tools/mdb_db3.py +48 -48
  32. re_common/baselibrary/tools/merge_file.py +171 -171
  33. re_common/baselibrary/tools/merge_gz_file.py +165 -165
  34. re_common/baselibrary/tools/mhdfstools/down_hdfs_files.py +42 -42
  35. re_common/baselibrary/tools/mhdfstools/hdfst.py +42 -42
  36. re_common/baselibrary/tools/mhdfstools/up_hdfs_files.py +38 -38
  37. re_common/baselibrary/tools/mongo_tools.py +50 -50
  38. re_common/baselibrary/tools/move_file.py +170 -170
  39. re_common/baselibrary/tools/move_mongo/mongo_table_to_file.py +63 -63
  40. re_common/baselibrary/tools/move_mongo/move_mongo_table.py +354 -354
  41. re_common/baselibrary/tools/move_mongo/use_mttf.py +18 -18
  42. re_common/baselibrary/tools/move_mongo/use_mv.py +93 -93
  43. re_common/baselibrary/tools/mpandas/mpandasreadexcel.py +125 -125
  44. re_common/baselibrary/tools/mpandas/pandas_visualization.py +7 -7
  45. re_common/baselibrary/tools/myparsel.py +104 -104
  46. re_common/baselibrary/tools/rename_dir_file.py +37 -37
  47. re_common/baselibrary/tools/sequoiadb_utils.py +398 -398
  48. re_common/baselibrary/tools/split_line_to_many.py +25 -25
  49. re_common/baselibrary/tools/stringtodicts.py +33 -33
  50. re_common/baselibrary/tools/workwechant_bot.py +84 -84
  51. re_common/baselibrary/utils/baseaiohttp.py +296 -296
  52. re_common/baselibrary/utils/baseaiomysql.py +87 -87
  53. re_common/baselibrary/utils/baseallstep.py +191 -191
  54. re_common/baselibrary/utils/baseavro.py +19 -19
  55. re_common/baselibrary/utils/baseboto3.py +291 -291
  56. re_common/baselibrary/utils/basecsv.py +32 -32
  57. re_common/baselibrary/utils/basedict.py +133 -133
  58. re_common/baselibrary/utils/basedir.py +241 -241
  59. re_common/baselibrary/utils/baseencode.py +351 -351
  60. re_common/baselibrary/utils/baseencoding.py +28 -28
  61. re_common/baselibrary/utils/baseesdsl.py +86 -86
  62. re_common/baselibrary/utils/baseexcel.py +264 -264
  63. re_common/baselibrary/utils/baseexcept.py +109 -109
  64. re_common/baselibrary/utils/basefile.py +654 -654
  65. re_common/baselibrary/utils/baseftp.py +214 -214
  66. re_common/baselibrary/utils/basegzip.py +60 -60
  67. re_common/baselibrary/utils/basehdfs.py +135 -135
  68. re_common/baselibrary/utils/basehttpx.py +268 -268
  69. re_common/baselibrary/utils/baseip.py +87 -87
  70. re_common/baselibrary/utils/basejson.py +2 -2
  71. re_common/baselibrary/utils/baselist.py +32 -32
  72. re_common/baselibrary/utils/basemotor.py +190 -190
  73. re_common/baselibrary/utils/basemssql.py +98 -98
  74. re_common/baselibrary/utils/baseodbc.py +113 -113
  75. re_common/baselibrary/utils/basepandas.py +302 -302
  76. re_common/baselibrary/utils/basepeewee.py +11 -11
  77. re_common/baselibrary/utils/basepika.py +180 -180
  78. re_common/baselibrary/utils/basepydash.py +143 -143
  79. re_common/baselibrary/utils/basepymongo.py +230 -230
  80. re_common/baselibrary/utils/basequeue.py +22 -22
  81. re_common/baselibrary/utils/baserar.py +57 -57
  82. re_common/baselibrary/utils/baserequest.py +279 -279
  83. re_common/baselibrary/utils/baseset.py +8 -8
  84. re_common/baselibrary/utils/basesmb.py +403 -403
  85. re_common/baselibrary/utils/basestring.py +382 -382
  86. re_common/baselibrary/utils/basetime.py +320 -320
  87. re_common/baselibrary/utils/baseurl.py +121 -121
  88. re_common/baselibrary/utils/basezip.py +57 -57
  89. re_common/baselibrary/utils/core/__init__.py +7 -7
  90. re_common/baselibrary/utils/core/bottomutils.py +18 -18
  91. re_common/baselibrary/utils/core/mdeprecated.py +327 -327
  92. re_common/baselibrary/utils/core/mlamada.py +16 -16
  93. re_common/baselibrary/utils/core/msginfo.py +25 -25
  94. re_common/baselibrary/utils/core/requests_core.py +103 -103
  95. re_common/baselibrary/utils/fateadm.py +429 -429
  96. re_common/baselibrary/utils/importfun.py +123 -123
  97. re_common/baselibrary/utils/mfaker.py +57 -57
  98. re_common/baselibrary/utils/my_abc/__init__.py +3 -3
  99. re_common/baselibrary/utils/my_abc/better_abc.py +32 -32
  100. re_common/baselibrary/utils/mylogger.py +414 -414
  101. re_common/baselibrary/utils/myredisclient.py +861 -861
  102. re_common/baselibrary/utils/pipupgrade.py +21 -21
  103. re_common/baselibrary/utils/ringlist.py +85 -85
  104. re_common/baselibrary/utils/version_compare.py +36 -36
  105. re_common/baselibrary/utils/ydmhttp.py +126 -126
  106. re_common/facade/lazy_import.py +11 -11
  107. re_common/facade/loggerfacade.py +25 -25
  108. re_common/facade/mysqlfacade.py +467 -467
  109. re_common/facade/now.py +31 -31
  110. re_common/facade/sqlite3facade.py +257 -257
  111. re_common/facade/use/mq_use_facade.py +83 -83
  112. re_common/facade/use/proxy_use_facade.py +19 -19
  113. re_common/libtest/base_dict_test.py +19 -19
  114. re_common/libtest/baseavro_test.py +13 -13
  115. re_common/libtest/basefile_test.py +14 -14
  116. re_common/libtest/basemssql_test.py +77 -77
  117. re_common/libtest/baseodbc_test.py +7 -7
  118. re_common/libtest/basepandas_test.py +38 -38
  119. re_common/libtest/get_attr_test/get_attr_test_settings.py +14 -14
  120. re_common/libtest/get_attr_test/settings.py +54 -54
  121. re_common/libtest/idencode_test.py +53 -53
  122. re_common/libtest/iniconfig_test.py +35 -35
  123. re_common/libtest/ip_test.py +34 -34
  124. re_common/libtest/merge_file_test.py +20 -20
  125. re_common/libtest/mfaker_test.py +8 -8
  126. re_common/libtest/mm3_test.py +31 -31
  127. re_common/libtest/mylogger_test.py +88 -88
  128. re_common/libtest/myparsel_test.py +27 -27
  129. re_common/libtest/mysql_test.py +151 -151
  130. re_common/libtest/pymongo_test.py +21 -21
  131. re_common/libtest/split_test.py +11 -11
  132. re_common/libtest/sqlite3_merge_test.py +5 -5
  133. re_common/libtest/sqlite3_test.py +34 -34
  134. re_common/libtest/tomlconfig_test.py +30 -30
  135. re_common/libtest/use_tools_test/__init__.py +2 -2
  136. re_common/libtest/user/__init__.py +4 -4
  137. re_common/studio/__init__.py +4 -4
  138. re_common/studio/assignment_expressions.py +36 -36
  139. re_common/studio/mydash/test1.py +18 -18
  140. re_common/studio/pydashstudio/first.py +9 -9
  141. re_common/studio/streamlitstudio/first_app.py +65 -65
  142. re_common/studio/streamlitstudio/uber_pickups.py +23 -23
  143. re_common/studio/test.py +18 -18
  144. re_common/v2/baselibrary/business_utils/BusinessStringUtil.py +219 -219
  145. re_common/v2/baselibrary/business_utils/baseencodeid.py +100 -100
  146. re_common/v2/baselibrary/business_utils/full_doi_path.py +116 -116
  147. re_common/v2/baselibrary/business_utils/rel_tools.py +6 -6
  148. re_common/v2/baselibrary/decorators/utils.py +59 -59
  149. re_common/v2/baselibrary/helpers/search_packge/NearestNeighbors_test.py +105 -105
  150. re_common/v2/baselibrary/helpers/search_packge/fit_text_match.py +253 -253
  151. re_common/v2/baselibrary/helpers/search_packge/scikit_learn_text_matcher.py +260 -260
  152. re_common/v2/baselibrary/helpers/search_packge/test.py +1 -1
  153. re_common/v2/baselibrary/s3object/baseboto3.py +230 -230
  154. re_common/v2/baselibrary/tools/WeChatRobot.py +95 -95
  155. re_common/v2/baselibrary/tools/ac_ahocorasick.py +75 -75
  156. re_common/v2/baselibrary/tools/concurrency.py +35 -35
  157. re_common/v2/baselibrary/tools/data_processer/base.py +53 -53
  158. re_common/v2/baselibrary/tools/data_processer/data_processer.py +508 -508
  159. re_common/v2/baselibrary/tools/data_processer/data_reader.py +187 -187
  160. re_common/v2/baselibrary/tools/data_processer/data_writer.py +38 -38
  161. re_common/v2/baselibrary/tools/dict_tools.py +44 -44
  162. re_common/v2/baselibrary/tools/dolphinscheduler.py +187 -187
  163. re_common/v2/baselibrary/tools/hdfs_base_processor.py +204 -204
  164. re_common/v2/baselibrary/tools/hdfs_bulk_processor.py +67 -67
  165. re_common/v2/baselibrary/tools/hdfs_data_processer.py +338 -338
  166. re_common/v2/baselibrary/tools/hdfs_line_processor.py +74 -74
  167. re_common/v2/baselibrary/tools/list_tools.py +69 -69
  168. re_common/v2/baselibrary/tools/resume_tracker.py +94 -94
  169. re_common/v2/baselibrary/tools/search_hash_tools.py +54 -54
  170. re_common/v2/baselibrary/tools/text_matcher.py +326 -326
  171. re_common/v2/baselibrary/tools/unionfind_tools.py +60 -60
  172. re_common/v2/baselibrary/utils/BusinessStringUtil.py +196 -196
  173. re_common/v2/baselibrary/utils/api_net_utils.py +270 -270
  174. re_common/v2/baselibrary/utils/author_smi.py +361 -361
  175. re_common/v2/baselibrary/utils/base_string_similarity.py +158 -158
  176. re_common/v2/baselibrary/utils/basedict.py +37 -37
  177. re_common/v2/baselibrary/utils/basehdfs.py +163 -163
  178. re_common/v2/baselibrary/utils/basepika.py +180 -180
  179. re_common/v2/baselibrary/utils/basetime.py +77 -77
  180. re_common/v2/baselibrary/utils/db.py +156 -156
  181. re_common/v2/baselibrary/utils/json_cls.py +16 -16
  182. re_common/v2/baselibrary/utils/mq.py +83 -83
  183. re_common/v2/baselibrary/utils/n_ary_expression_tree.py +243 -243
  184. re_common/v2/baselibrary/utils/string_bool.py +186 -186
  185. re_common/v2/baselibrary/utils/string_clear.py +246 -246
  186. re_common/v2/baselibrary/utils/string_smi.py +18 -18
  187. re_common/v2/baselibrary/utils/stringutils.py +271 -278
  188. re_common/vip/base_step_process.py +11 -11
  189. re_common/vip/baseencodeid.py +90 -90
  190. re_common/vip/changetaskname.py +28 -28
  191. re_common/vip/core_var.py +24 -24
  192. re_common/vip/mmh3Hash.py +89 -89
  193. re_common/vip/proxy/allproxys.py +127 -127
  194. re_common/vip/proxy/allproxys_thread.py +159 -159
  195. re_common/vip/proxy/cnki_proxy.py +153 -153
  196. re_common/vip/proxy/kuaidaili.py +87 -87
  197. re_common/vip/proxy/proxy_all.py +113 -113
  198. re_common/vip/proxy/update_kuaidaili_0.py +42 -42
  199. re_common/vip/proxy/wanfang_proxy.py +152 -152
  200. re_common/vip/proxy/wp_proxy_all.py +181 -181
  201. re_common/vip/read_rawid_to_txt.py +91 -91
  202. re_common/vip/title/__init__.py +5 -5
  203. re_common/vip/title/transform/TransformBookTitleToZt.py +125 -125
  204. re_common/vip/title/transform/TransformConferenceTitleToZt.py +139 -139
  205. re_common/vip/title/transform/TransformCstadTitleToZt.py +195 -195
  206. re_common/vip/title/transform/TransformJournalTitleToZt.py +203 -203
  207. re_common/vip/title/transform/TransformPatentTitleToZt.py +132 -132
  208. re_common/vip/title/transform/TransformRegulationTitleToZt.py +114 -114
  209. re_common/vip/title/transform/TransformStandardTitleToZt.py +135 -135
  210. re_common/vip/title/transform/TransformThesisTitleToZt.py +135 -135
  211. re_common/vip/title/transform/__init__.py +10 -10
  212. {re_common-10.0.37.dist-info → re_common-10.0.39.dist-info}/LICENSE +201 -201
  213. {re_common-10.0.37.dist-info → re_common-10.0.39.dist-info}/METADATA +16 -16
  214. re_common-10.0.39.dist-info/RECORD +248 -0
  215. {re_common-10.0.37.dist-info → re_common-10.0.39.dist-info}/WHEEL +1 -1
  216. re_common-10.0.37.dist-info/RECORD +0 -248
  217. {re_common-10.0.37.dist-info → re_common-10.0.39.dist-info}/top_level.txt +0 -0
@@ -1,244 +1,244 @@
1
- class Node:
2
- def __init__(self, value, children=None):
3
- self.value = value
4
- self.children = children if children is not None else []
5
-
6
- def __repr__(self):
7
- return f"Node(value={self.value}, children={self.children})"
8
-
9
-
10
- def tokenize(expression):
11
- """将表达式分解为标记(token),仅以 and, or, not 和括号作为分界符
12
-
13
- Args:
14
- expression (str): 输入的字符串表达式,例如 'a = 3 + (b > 2) and c'
15
-
16
- Returns:
17
- list: 分解后的标记列表,例如 ['a = 3 + (b > 2)', 'and', 'c']
18
- """
19
- tokens = [] # 存储最终的标记列表
20
- current = "" # 当前正在构建的标记字符串
21
- i = 0 # 当前字符的索引
22
- length = len(expression) # 输入表达式的长度
23
-
24
- def is_delimiter_match(expression, i, delimiter_len=3, delimiter="and"):
25
- """检查当前位置是否匹配指定的分隔符(and, or, not)
26
-
27
- Args:
28
- expression (str): 输入的表达式字符串
29
- i (int): 当前检查的起始索引
30
- delimiter_len (int): 分隔符的长度,默认为 3(适用于 'and' 和 'not')
31
- delimiter (str): 要检查的分隔符,默认为 'and'
32
-
33
- Returns:
34
- bool: 如果当前位置匹配分隔符且前后有空格,返回 True,否则返回 False
35
- """
36
- # 检查索引是否超出范围
37
- if not i + delimiter_len <= length:
38
- return False
39
- # 检查当前位置是否匹配指定分隔符(忽略大小写)
40
- if not expression[i:i + delimiter_len].lower() == delimiter:
41
- return False
42
-
43
- # 检查分隔符前是否有一个空格(如果不是字符串开头)
44
- if i - 1 >= 0:
45
- if not expression[i - 1].lower() == ' ':
46
- return False
47
-
48
- # 检查分隔符后是否有一个空格(如果不是字符串结尾)
49
- if i + delimiter_len + 1 <= length:
50
- if not expression[i + delimiter_len].lower() == ' ':
51
- return False
52
- return True
53
-
54
- # 遍历表达式的每个字符
55
- while i < length:
56
- char = expression[i] # 当前处理的字符
57
-
58
- # 处理括号
59
- if char in "()":
60
- if current.strip(): # 如果当前标记有内容,先将其添加到 tokens
61
- tokens.append(current.strip())
62
- current = "" # 重置当前标记
63
- tokens.append(char) # 将括号作为独立标记添加
64
- i += 1 # 移动到下一个字符
65
- continue
66
-
67
- # 检查是否遇到 and, or, not 分隔符
68
- if is_delimiter_match(expression, i, delimiter_len=3, delimiter="and"):
69
- if current.strip(): # 如果当前标记有内容,先添加
70
- tokens.append(current.strip())
71
- current = "" # 重置当前标记
72
- tokens.append("and") # 添加 'and' 标记
73
- i += 3 # 跳过 'and' 的长度
74
- continue
75
- elif is_delimiter_match(expression, i, delimiter_len=2, delimiter="or"):
76
- if current.strip(): # 如果当前标记有内容,先添加
77
- tokens.append(current.strip())
78
- current = "" # 重置当前标记
79
- tokens.append("or") # 添加 'or' 标记
80
- i += 2 # 跳过 'or' 的长度
81
- continue
82
- elif is_delimiter_match(expression, i, delimiter_len=3, delimiter="not"):
83
- if current.strip(): # 如果当前标记有内容,先添加
84
- tokens.append(current.strip())
85
- current = "" # 重置当前标记
86
- tokens.append("not") # 添加 'not' 标记
87
- i += 3 # 跳过 'not' 的长度
88
- continue
89
-
90
- # 将非分隔符字符追加到当前标记中,包括空格
91
- current += char
92
- i += 1 # 移动到下一个字符
93
-
94
- # 处理最后一个标记(如果有内容)
95
- if current.strip():
96
- tokens.append(current.strip())
97
-
98
- return tokens # 返回标记列表
99
-
100
-
101
-
102
-
103
- def parse_expression(tokens):
104
- """递归下降解析表达式"""
105
-
106
- def parse_or(tokens, pos):
107
- """解析 OR 级别(最低优先级)"""
108
- left, pos = parse_and(tokens, pos)
109
- while pos < len(tokens) and tokens[pos] == 'or':
110
- pos += 1
111
- if pos >= len(tokens):
112
- raise ValueError("Incomplete expression after 'or'")
113
- right, pos = parse_and(tokens, pos)
114
- left = Node('or', [left, right])
115
- return left, pos
116
-
117
- def parse_and(tokens, pos):
118
- """解析 AND 级别(次高优先级)"""
119
- left, pos = parse_not(tokens, pos)
120
- while pos < len(tokens) and tokens[pos] == 'and':
121
- pos += 1
122
- if pos >= len(tokens):
123
- raise ValueError("Incomplete expression after 'and'")
124
- right, pos = parse_not(tokens, pos)
125
- left = Node('and', [left, right])
126
- return left, pos
127
-
128
- def parse_not(tokens, pos):
129
- """解析 NOT 级别(最高优先级)"""
130
- if pos < len(tokens) and tokens[pos] == 'not':
131
- pos += 1
132
- if pos >= len(tokens):
133
- raise ValueError("Incomplete expression after 'not'")
134
- child, pos = parse_primary(tokens, pos)
135
- return Node('not', [child]), pos
136
- return parse_primary(tokens, pos)
137
-
138
- def parse_primary(tokens, pos):
139
- """解析基本单元(条件或括号表达式)"""
140
- if pos >= len(tokens):
141
- raise ValueError("Unexpected end of expression")
142
-
143
- if tokens[pos] == '(':
144
- pos += 1
145
- subtree, pos = parse_or(tokens, pos)
146
- if pos >= len(tokens) or tokens[pos] != ')':
147
- raise ValueError("Missing closing parenthesis")
148
- return subtree, pos + 1
149
- else:
150
- # 假设这是一个条件(如 A=1)
151
- return Node(tokens[pos]), pos + 1
152
-
153
- # 从头开始解析
154
- tree, pos = parse_or(tokens, 0)
155
- if pos < len(tokens):
156
- raise ValueError(f"Extra tokens after expression: {tokens[pos:]}")
157
- return tree
158
-
159
-
160
- def flatten_tree(node):
161
- """清理语法树,将嵌套的同级 and/or 节点展平。
162
-
163
- Args:
164
- node (Node): 输入的语法树节点
165
-
166
- Returns:
167
- Node: 清理后的新语法树节点
168
- """
169
- # 如果没有子节点,直接返回原节点(条件节点)
170
- if not node.children:
171
- return Node(value=node.value, children=[])
172
-
173
- # 递归清理所有子节点
174
- cleaned_children = [flatten_tree(child) for child in node.children]
175
-
176
- # 如果当前节点是 'and' 或 'or',展平嵌套的同类节点
177
- if node.value in ('and', 'or'):
178
- flattened_children = []
179
- for child in cleaned_children:
180
- # 如果子节点的值与当前节点相同(例如 'or' 下的 'or'),将其子节点提升
181
- if child.value == node.value:
182
- flattened_children.extend(child.children)
183
- else:
184
- flattened_children.append(child)
185
- return Node(value=node.value, children=flattened_children)
186
-
187
- # 对于其他节点(例如 'not'),保持结构不变,只更新子节点
188
- return Node(value=node.value, children=cleaned_children)
189
-
190
-
191
- def pretty_print_tree(node, indent=0, prefix=""):
192
- """生成语法树的格式化字符串表示,带有层次缩进。
193
-
194
- Args:
195
- node (Node): 要格式化的语法树节点
196
- indent (int): 当前缩进级别(空格数),默认从 0 开始
197
- prefix (str): 前缀字符串,用于表示当前行的开头
198
-
199
- Returns:
200
- str: 格式化后的树形字符串
201
- """
202
- # 基本缩进单位
203
- spaces = " " * indent
204
-
205
- # 如果没有子节点,返回单行表示
206
- if not node.children:
207
- return f"{spaces}{prefix}Node(value='{node.value}', children=[])"
208
-
209
- # 构建当前节点的字符串
210
- result = [f"{spaces}{prefix}Node(value='{node.value}', children=["]
211
-
212
- # 递归处理每个子节点
213
- for i, child in enumerate(node.children):
214
- is_last = i == len(node.children) - 1
215
- child_prefix = " " if is_last else " "
216
- result.append(pretty_print_tree(child, indent + 4, child_prefix))
217
-
218
- # 添加结束括号
219
- result.append(f"{spaces}])")
220
-
221
- # 将所有行连接成一个字符串
222
- return "\n".join(result)
223
-
224
- # 测试代码
225
- expressions = [
226
- "not A=1 and B= 2",
227
- "A=1 and (not B=2 or (C=3 or D=4))",
228
- "A=1 and not (B=2 or C=3 and D=4 or E=5)",
229
- "(A=1 and not (B=2 or C=3 or D=4))",
230
- "A=1 and", # 不完整表达式
231
- "and A=1", # 不完整表达式
232
- ]
233
-
234
- for expr in expressions:
235
- try:
236
- print(f"\nExpression: {expr}")
237
- tokens = tokenize(expr)
238
- print("Tokens:", tokens)
239
- tree = parse_expression(tokens)
240
- tree = flatten_tree(tree)
241
- tree = pretty_print_tree(tree)
242
- print("Tree:", tree)
243
- except ValueError as e:
1
+ class Node:
2
+ def __init__(self, value, children=None):
3
+ self.value = value
4
+ self.children = children if children is not None else []
5
+
6
+ def __repr__(self):
7
+ return f"Node(value={self.value}, children={self.children})"
8
+
9
+
10
+ def tokenize(expression):
11
+ """将表达式分解为标记(token),仅以 and, or, not 和括号作为分界符
12
+
13
+ Args:
14
+ expression (str): 输入的字符串表达式,例如 'a = 3 + (b > 2) and c'
15
+
16
+ Returns:
17
+ list: 分解后的标记列表,例如 ['a = 3 + (b > 2)', 'and', 'c']
18
+ """
19
+ tokens = [] # 存储最终的标记列表
20
+ current = "" # 当前正在构建的标记字符串
21
+ i = 0 # 当前字符的索引
22
+ length = len(expression) # 输入表达式的长度
23
+
24
+ def is_delimiter_match(expression, i, delimiter_len=3, delimiter="and"):
25
+ """检查当前位置是否匹配指定的分隔符(and, or, not)
26
+
27
+ Args:
28
+ expression (str): 输入的表达式字符串
29
+ i (int): 当前检查的起始索引
30
+ delimiter_len (int): 分隔符的长度,默认为 3(适用于 'and' 和 'not')
31
+ delimiter (str): 要检查的分隔符,默认为 'and'
32
+
33
+ Returns:
34
+ bool: 如果当前位置匹配分隔符且前后有空格,返回 True,否则返回 False
35
+ """
36
+ # 检查索引是否超出范围
37
+ if not i + delimiter_len <= length:
38
+ return False
39
+ # 检查当前位置是否匹配指定分隔符(忽略大小写)
40
+ if not expression[i:i + delimiter_len].lower() == delimiter:
41
+ return False
42
+
43
+ # 检查分隔符前是否有一个空格(如果不是字符串开头)
44
+ if i - 1 >= 0:
45
+ if not expression[i - 1].lower() == ' ':
46
+ return False
47
+
48
+ # 检查分隔符后是否有一个空格(如果不是字符串结尾)
49
+ if i + delimiter_len + 1 <= length:
50
+ if not expression[i + delimiter_len].lower() == ' ':
51
+ return False
52
+ return True
53
+
54
+ # 遍历表达式的每个字符
55
+ while i < length:
56
+ char = expression[i] # 当前处理的字符
57
+
58
+ # 处理括号
59
+ if char in "()":
60
+ if current.strip(): # 如果当前标记有内容,先将其添加到 tokens
61
+ tokens.append(current.strip())
62
+ current = "" # 重置当前标记
63
+ tokens.append(char) # 将括号作为独立标记添加
64
+ i += 1 # 移动到下一个字符
65
+ continue
66
+
67
+ # 检查是否遇到 and, or, not 分隔符
68
+ if is_delimiter_match(expression, i, delimiter_len=3, delimiter="and"):
69
+ if current.strip(): # 如果当前标记有内容,先添加
70
+ tokens.append(current.strip())
71
+ current = "" # 重置当前标记
72
+ tokens.append("and") # 添加 'and' 标记
73
+ i += 3 # 跳过 'and' 的长度
74
+ continue
75
+ elif is_delimiter_match(expression, i, delimiter_len=2, delimiter="or"):
76
+ if current.strip(): # 如果当前标记有内容,先添加
77
+ tokens.append(current.strip())
78
+ current = "" # 重置当前标记
79
+ tokens.append("or") # 添加 'or' 标记
80
+ i += 2 # 跳过 'or' 的长度
81
+ continue
82
+ elif is_delimiter_match(expression, i, delimiter_len=3, delimiter="not"):
83
+ if current.strip(): # 如果当前标记有内容,先添加
84
+ tokens.append(current.strip())
85
+ current = "" # 重置当前标记
86
+ tokens.append("not") # 添加 'not' 标记
87
+ i += 3 # 跳过 'not' 的长度
88
+ continue
89
+
90
+ # 将非分隔符字符追加到当前标记中,包括空格
91
+ current += char
92
+ i += 1 # 移动到下一个字符
93
+
94
+ # 处理最后一个标记(如果有内容)
95
+ if current.strip():
96
+ tokens.append(current.strip())
97
+
98
+ return tokens # 返回标记列表
99
+
100
+
101
+
102
+
103
+ def parse_expression(tokens):
104
+ """递归下降解析表达式"""
105
+
106
+ def parse_or(tokens, pos):
107
+ """解析 OR 级别(最低优先级)"""
108
+ left, pos = parse_and(tokens, pos)
109
+ while pos < len(tokens) and tokens[pos] == 'or':
110
+ pos += 1
111
+ if pos >= len(tokens):
112
+ raise ValueError("Incomplete expression after 'or'")
113
+ right, pos = parse_and(tokens, pos)
114
+ left = Node('or', [left, right])
115
+ return left, pos
116
+
117
+ def parse_and(tokens, pos):
118
+ """解析 AND 级别(次高优先级)"""
119
+ left, pos = parse_not(tokens, pos)
120
+ while pos < len(tokens) and tokens[pos] == 'and':
121
+ pos += 1
122
+ if pos >= len(tokens):
123
+ raise ValueError("Incomplete expression after 'and'")
124
+ right, pos = parse_not(tokens, pos)
125
+ left = Node('and', [left, right])
126
+ return left, pos
127
+
128
+ def parse_not(tokens, pos):
129
+ """解析 NOT 级别(最高优先级)"""
130
+ if pos < len(tokens) and tokens[pos] == 'not':
131
+ pos += 1
132
+ if pos >= len(tokens):
133
+ raise ValueError("Incomplete expression after 'not'")
134
+ child, pos = parse_primary(tokens, pos)
135
+ return Node('not', [child]), pos
136
+ return parse_primary(tokens, pos)
137
+
138
+ def parse_primary(tokens, pos):
139
+ """解析基本单元(条件或括号表达式)"""
140
+ if pos >= len(tokens):
141
+ raise ValueError("Unexpected end of expression")
142
+
143
+ if tokens[pos] == '(':
144
+ pos += 1
145
+ subtree, pos = parse_or(tokens, pos)
146
+ if pos >= len(tokens) or tokens[pos] != ')':
147
+ raise ValueError("Missing closing parenthesis")
148
+ return subtree, pos + 1
149
+ else:
150
+ # 假设这是一个条件(如 A=1)
151
+ return Node(tokens[pos]), pos + 1
152
+
153
+ # 从头开始解析
154
+ tree, pos = parse_or(tokens, 0)
155
+ if pos < len(tokens):
156
+ raise ValueError(f"Extra tokens after expression: {tokens[pos:]}")
157
+ return tree
158
+
159
+
160
+ def flatten_tree(node):
161
+ """清理语法树,将嵌套的同级 and/or 节点展平。
162
+
163
+ Args:
164
+ node (Node): 输入的语法树节点
165
+
166
+ Returns:
167
+ Node: 清理后的新语法树节点
168
+ """
169
+ # 如果没有子节点,直接返回原节点(条件节点)
170
+ if not node.children:
171
+ return Node(value=node.value, children=[])
172
+
173
+ # 递归清理所有子节点
174
+ cleaned_children = [flatten_tree(child) for child in node.children]
175
+
176
+ # 如果当前节点是 'and' 或 'or',展平嵌套的同类节点
177
+ if node.value in ('and', 'or'):
178
+ flattened_children = []
179
+ for child in cleaned_children:
180
+ # 如果子节点的值与当前节点相同(例如 'or' 下的 'or'),将其子节点提升
181
+ if child.value == node.value:
182
+ flattened_children.extend(child.children)
183
+ else:
184
+ flattened_children.append(child)
185
+ return Node(value=node.value, children=flattened_children)
186
+
187
+ # 对于其他节点(例如 'not'),保持结构不变,只更新子节点
188
+ return Node(value=node.value, children=cleaned_children)
189
+
190
+
191
+ def pretty_print_tree(node, indent=0, prefix=""):
192
+ """生成语法树的格式化字符串表示,带有层次缩进。
193
+
194
+ Args:
195
+ node (Node): 要格式化的语法树节点
196
+ indent (int): 当前缩进级别(空格数),默认从 0 开始
197
+ prefix (str): 前缀字符串,用于表示当前行的开头
198
+
199
+ Returns:
200
+ str: 格式化后的树形字符串
201
+ """
202
+ # 基本缩进单位
203
+ spaces = " " * indent
204
+
205
+ # 如果没有子节点,返回单行表示
206
+ if not node.children:
207
+ return f"{spaces}{prefix}Node(value='{node.value}', children=[])"
208
+
209
+ # 构建当前节点的字符串
210
+ result = [f"{spaces}{prefix}Node(value='{node.value}', children=["]
211
+
212
+ # 递归处理每个子节点
213
+ for i, child in enumerate(node.children):
214
+ is_last = i == len(node.children) - 1
215
+ child_prefix = " " if is_last else " "
216
+ result.append(pretty_print_tree(child, indent + 4, child_prefix))
217
+
218
+ # 添加结束括号
219
+ result.append(f"{spaces}])")
220
+
221
+ # 将所有行连接成一个字符串
222
+ return "\n".join(result)
223
+
224
+ # 测试代码
225
+ expressions = [
226
+ "not A=1 and B= 2",
227
+ "A=1 and (not B=2 or (C=3 or D=4))",
228
+ "A=1 and not (B=2 or C=3 and D=4 or E=5)",
229
+ "(A=1 and not (B=2 or C=3 or D=4))",
230
+ "A=1 and", # 不完整表达式
231
+ "and A=1", # 不完整表达式
232
+ ]
233
+
234
+ for expr in expressions:
235
+ try:
236
+ print(f"\nExpression: {expr}")
237
+ tokens = tokenize(expr)
238
+ print("Tokens:", tokens)
239
+ tree = parse_expression(tokens)
240
+ tree = flatten_tree(tree)
241
+ tree = pretty_print_tree(tree)
242
+ print("Tree:", tree)
243
+ except ValueError as e:
244
244
  print(f"Error: {e}")