re-common 10.0.22__py3-none-any.whl → 10.0.24__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.
- re_common/baselibrary/__init__.py +4 -4
- re_common/baselibrary/baseabs/__init__.py +6 -6
- re_common/baselibrary/baseabs/baseabs.py +26 -26
- re_common/baselibrary/database/mbuilder.py +132 -132
- re_common/baselibrary/database/moudle.py +93 -93
- re_common/baselibrary/database/msqlite3.py +194 -194
- re_common/baselibrary/database/mysql.py +169 -169
- re_common/baselibrary/database/sql_factory.py +26 -26
- re_common/baselibrary/mthread/MThreadingRun.py +486 -486
- re_common/baselibrary/mthread/MThreadingRunEvent.py +349 -349
- re_common/baselibrary/mthread/__init__.py +2 -2
- re_common/baselibrary/mthread/mythreading.py +695 -695
- re_common/baselibrary/pakge_other/socks.py +404 -404
- re_common/baselibrary/readconfig/config_factory.py +18 -18
- re_common/baselibrary/readconfig/ini_config.py +317 -317
- re_common/baselibrary/readconfig/toml_config.py +49 -49
- re_common/baselibrary/temporary/envdata.py +36 -36
- re_common/baselibrary/tools/all_requests/aiohttp_request.py +118 -118
- re_common/baselibrary/tools/all_requests/httpx_requet.py +102 -102
- re_common/baselibrary/tools/all_requests/mrequest.py +412 -412
- re_common/baselibrary/tools/all_requests/requests_request.py +81 -81
- re_common/baselibrary/tools/batch_compre/bijiao_batch.py +31 -31
- re_common/baselibrary/tools/contrast_db3.py +123 -123
- re_common/baselibrary/tools/copy_file.py +39 -39
- re_common/baselibrary/tools/db3_2_sizedb3.py +102 -102
- re_common/baselibrary/tools/foreachgz.py +39 -39
- re_common/baselibrary/tools/get_attr.py +10 -10
- re_common/baselibrary/tools/image_to_pdf.py +61 -61
- re_common/baselibrary/tools/java_code_deal.py +139 -139
- re_common/baselibrary/tools/javacode.py +79 -79
- re_common/baselibrary/tools/mdb_db3.py +48 -48
- re_common/baselibrary/tools/merge_file.py +171 -171
- re_common/baselibrary/tools/merge_gz_file.py +165 -165
- re_common/baselibrary/tools/mhdfstools/down_hdfs_files.py +42 -42
- re_common/baselibrary/tools/mhdfstools/hdfst.py +42 -42
- re_common/baselibrary/tools/mhdfstools/up_hdfs_files.py +38 -38
- re_common/baselibrary/tools/mongo_tools.py +50 -50
- re_common/baselibrary/tools/move_file.py +170 -170
- re_common/baselibrary/tools/move_mongo/mongo_table_to_file.py +63 -63
- re_common/baselibrary/tools/move_mongo/move_mongo_table.py +354 -354
- re_common/baselibrary/tools/move_mongo/use_mttf.py +18 -18
- re_common/baselibrary/tools/move_mongo/use_mv.py +93 -93
- re_common/baselibrary/tools/mpandas/mpandasreadexcel.py +125 -125
- re_common/baselibrary/tools/mpandas/pandas_visualization.py +7 -7
- re_common/baselibrary/tools/myparsel.py +104 -104
- re_common/baselibrary/tools/rename_dir_file.py +37 -37
- re_common/baselibrary/tools/sequoiadb_utils.py +398 -398
- re_common/baselibrary/tools/split_line_to_many.py +25 -25
- re_common/baselibrary/tools/stringtodicts.py +33 -33
- re_common/baselibrary/tools/workwechant_bot.py +84 -84
- re_common/baselibrary/utils/baseaiohttp.py +296 -296
- re_common/baselibrary/utils/baseaiomysql.py +87 -87
- re_common/baselibrary/utils/baseallstep.py +191 -191
- re_common/baselibrary/utils/baseavro.py +19 -19
- re_common/baselibrary/utils/baseboto3.py +291 -291
- re_common/baselibrary/utils/basecsv.py +32 -32
- re_common/baselibrary/utils/basedict.py +133 -133
- re_common/baselibrary/utils/basedir.py +241 -241
- re_common/baselibrary/utils/baseencode.py +351 -351
- re_common/baselibrary/utils/baseencoding.py +28 -28
- re_common/baselibrary/utils/baseesdsl.py +86 -86
- re_common/baselibrary/utils/baseexcel.py +264 -264
- re_common/baselibrary/utils/baseexcept.py +109 -109
- re_common/baselibrary/utils/basefile.py +654 -654
- re_common/baselibrary/utils/baseftp.py +214 -214
- re_common/baselibrary/utils/basegzip.py +60 -60
- re_common/baselibrary/utils/basehdfs.py +135 -135
- re_common/baselibrary/utils/basehttpx.py +268 -268
- re_common/baselibrary/utils/baseip.py +87 -87
- re_common/baselibrary/utils/basejson.py +2 -2
- re_common/baselibrary/utils/baselist.py +32 -32
- re_common/baselibrary/utils/basemotor.py +190 -190
- re_common/baselibrary/utils/basemssql.py +98 -98
- re_common/baselibrary/utils/baseodbc.py +113 -113
- re_common/baselibrary/utils/basepandas.py +302 -302
- re_common/baselibrary/utils/basepeewee.py +11 -11
- re_common/baselibrary/utils/basepika.py +180 -180
- re_common/baselibrary/utils/basepydash.py +143 -143
- re_common/baselibrary/utils/basepymongo.py +230 -230
- re_common/baselibrary/utils/basequeue.py +22 -22
- re_common/baselibrary/utils/baserar.py +57 -57
- re_common/baselibrary/utils/baserequest.py +279 -279
- re_common/baselibrary/utils/baseset.py +8 -8
- re_common/baselibrary/utils/basesmb.py +403 -403
- re_common/baselibrary/utils/basestring.py +382 -382
- re_common/baselibrary/utils/basetime.py +320 -320
- re_common/baselibrary/utils/baseurl.py +121 -121
- re_common/baselibrary/utils/basezip.py +57 -57
- re_common/baselibrary/utils/core/__init__.py +7 -7
- re_common/baselibrary/utils/core/bottomutils.py +18 -18
- re_common/baselibrary/utils/core/mdeprecated.py +327 -327
- re_common/baselibrary/utils/core/mlamada.py +16 -16
- re_common/baselibrary/utils/core/msginfo.py +25 -25
- re_common/baselibrary/utils/core/requests_core.py +103 -103
- re_common/baselibrary/utils/fateadm.py +429 -429
- re_common/baselibrary/utils/importfun.py +123 -123
- re_common/baselibrary/utils/mfaker.py +57 -57
- re_common/baselibrary/utils/my_abc/__init__.py +3 -3
- re_common/baselibrary/utils/my_abc/better_abc.py +32 -32
- re_common/baselibrary/utils/mylogger.py +414 -414
- re_common/baselibrary/utils/myredisclient.py +861 -861
- re_common/baselibrary/utils/pipupgrade.py +21 -21
- re_common/baselibrary/utils/ringlist.py +85 -85
- re_common/baselibrary/utils/version_compare.py +36 -36
- re_common/baselibrary/utils/ydmhttp.py +126 -126
- re_common/facade/lazy_import.py +11 -11
- re_common/facade/loggerfacade.py +25 -25
- re_common/facade/mysqlfacade.py +467 -467
- re_common/facade/now.py +31 -31
- re_common/facade/sqlite3facade.py +257 -257
- re_common/facade/use/mq_use_facade.py +83 -83
- re_common/facade/use/proxy_use_facade.py +19 -19
- re_common/libtest/base_dict_test.py +19 -19
- re_common/libtest/baseavro_test.py +13 -13
- re_common/libtest/basefile_test.py +14 -14
- re_common/libtest/basemssql_test.py +77 -77
- re_common/libtest/baseodbc_test.py +7 -7
- re_common/libtest/basepandas_test.py +38 -38
- re_common/libtest/get_attr_test/get_attr_test_settings.py +14 -14
- re_common/libtest/get_attr_test/settings.py +54 -54
- re_common/libtest/idencode_test.py +53 -53
- re_common/libtest/iniconfig_test.py +35 -35
- re_common/libtest/ip_test.py +34 -34
- re_common/libtest/merge_file_test.py +20 -20
- re_common/libtest/mfaker_test.py +8 -8
- re_common/libtest/mm3_test.py +31 -31
- re_common/libtest/mylogger_test.py +88 -88
- re_common/libtest/myparsel_test.py +27 -27
- re_common/libtest/mysql_test.py +151 -151
- re_common/libtest/pymongo_test.py +21 -21
- re_common/libtest/split_test.py +11 -11
- re_common/libtest/sqlite3_merge_test.py +5 -5
- re_common/libtest/sqlite3_test.py +34 -34
- re_common/libtest/tomlconfig_test.py +30 -30
- re_common/libtest/use_tools_test/__init__.py +2 -2
- re_common/libtest/user/__init__.py +4 -4
- re_common/studio/__init__.py +4 -4
- re_common/studio/assignment_expressions.py +36 -36
- re_common/studio/mydash/test1.py +18 -18
- re_common/studio/pydashstudio/first.py +9 -9
- re_common/studio/streamlitstudio/first_app.py +65 -65
- re_common/studio/streamlitstudio/uber_pickups.py +23 -23
- re_common/studio/test.py +18 -18
- re_common/v2/baselibrary/business_utils/BusinessStringUtil.py +195 -0
- re_common/v2/baselibrary/business_utils/__init__.py +0 -0
- re_common/v2/baselibrary/business_utils/rel_tools.py +6 -0
- re_common/v2/baselibrary/decorators/utils.py +59 -59
- re_common/v2/baselibrary/s3object/baseboto3.py +230 -230
- re_common/v2/baselibrary/tools/WeChatRobot.py +95 -79
- re_common/v2/baselibrary/tools/ac_ahocorasick.py +75 -75
- re_common/v2/baselibrary/tools/dict_tools.py +37 -37
- re_common/v2/baselibrary/tools/dolphinscheduler.py +187 -187
- re_common/v2/baselibrary/tools/hdfs_data_processer.py +338 -338
- re_common/v2/baselibrary/tools/list_tools.py +65 -65
- re_common/v2/baselibrary/tools/search_hash_tools.py +54 -54
- re_common/v2/baselibrary/tools/text_matcher.py +326 -326
- re_common/v2/baselibrary/tools/unionfind_tools.py +60 -60
- re_common/v2/baselibrary/utils/BusinessStringUtil.py +196 -196
- re_common/v2/baselibrary/utils/author_smi.py +360 -360
- re_common/v2/baselibrary/utils/base_string_similarity.py +158 -158
- re_common/v2/baselibrary/utils/basedict.py +37 -37
- re_common/v2/baselibrary/utils/basehdfs.py +161 -161
- re_common/v2/baselibrary/utils/basepika.py +180 -180
- re_common/v2/baselibrary/utils/basetime.py +77 -77
- re_common/v2/baselibrary/utils/db.py +38 -38
- re_common/v2/baselibrary/utils/json_cls.py +16 -16
- re_common/v2/baselibrary/utils/mq.py +83 -83
- re_common/v2/baselibrary/utils/n_ary_expression_tree.py +243 -243
- re_common/v2/baselibrary/utils/string_bool.py +186 -149
- re_common/v2/baselibrary/utils/string_clear.py +227 -204
- re_common/v2/baselibrary/utils/string_smi.py +18 -18
- re_common/v2/baselibrary/utils/stringutils.py +213 -213
- re_common/vip/base_step_process.py +11 -11
- re_common/vip/baseencodeid.py +90 -90
- re_common/vip/changetaskname.py +28 -28
- re_common/vip/core_var.py +24 -24
- re_common/vip/mmh3Hash.py +89 -89
- re_common/vip/proxy/allproxys.py +127 -127
- re_common/vip/proxy/allproxys_thread.py +159 -159
- re_common/vip/proxy/cnki_proxy.py +153 -153
- re_common/vip/proxy/kuaidaili.py +87 -87
- re_common/vip/proxy/proxy_all.py +113 -113
- re_common/vip/proxy/update_kuaidaili_0.py +42 -42
- re_common/vip/proxy/wanfang_proxy.py +152 -152
- re_common/vip/proxy/wp_proxy_all.py +181 -181
- re_common/vip/read_rawid_to_txt.py +91 -91
- re_common/vip/title/__init__.py +5 -5
- re_common/vip/title/transform/TransformBookTitleToZt.py +125 -125
- re_common/vip/title/transform/TransformConferenceTitleToZt.py +139 -139
- re_common/vip/title/transform/TransformCstadTitleToZt.py +195 -195
- re_common/vip/title/transform/TransformJournalTitleToZt.py +203 -203
- re_common/vip/title/transform/TransformPatentTitleToZt.py +132 -132
- re_common/vip/title/transform/TransformRegulationTitleToZt.py +114 -114
- re_common/vip/title/transform/TransformStandardTitleToZt.py +135 -135
- re_common/vip/title/transform/TransformThesisTitleToZt.py +135 -135
- re_common/vip/title/transform/__init__.py +10 -10
- {re_common-10.0.22.dist-info → re_common-10.0.24.dist-info}/LICENSE +201 -201
- {re_common-10.0.22.dist-info → re_common-10.0.24.dist-info}/METADATA +16 -16
- re_common-10.0.24.dist-info/RECORD +230 -0
- {re_common-10.0.22.dist-info → re_common-10.0.24.dist-info}/WHEEL +1 -1
- re_common-10.0.22.dist-info/RECORD +0 -227
- {re_common-10.0.22.dist-info → re_common-10.0.24.dist-info}/top_level.txt +0 -0
|
@@ -1,83 +1,83 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
import traceback
|
|
3
|
-
|
|
4
|
-
from re_common.v2.baselibrary.utils.basepika import BasePika
|
|
5
|
-
from retry import retry
|
|
6
|
-
|
|
7
|
-
logging_logger = logging.getLogger(__name__)
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class UseMq(object):
|
|
11
|
-
|
|
12
|
-
def __init__(self, queue, qos=1):
|
|
13
|
-
self.queue = queue
|
|
14
|
-
self.qos = qos
|
|
15
|
-
self.basepika = BasePika()
|
|
16
|
-
self.basepika.set_default()
|
|
17
|
-
self.basepika.connect()
|
|
18
|
-
self.basepika.create_channel()
|
|
19
|
-
self.basepika.queue_declare(queue=queue, durable=True)
|
|
20
|
-
self.basepika.basic_qos(qos)
|
|
21
|
-
self.properties = self.basepika.get_properties()
|
|
22
|
-
|
|
23
|
-
def re_conn(self):
|
|
24
|
-
"""
|
|
25
|
-
重新连接
|
|
26
|
-
:return:
|
|
27
|
-
"""
|
|
28
|
-
self.basepika.connect()
|
|
29
|
-
self.basepika.create_channel()
|
|
30
|
-
self.basepika.queue_declare(queue=self.queue, durable=True)
|
|
31
|
-
self.basepika.basic_qos(self.qos)
|
|
32
|
-
|
|
33
|
-
@retry(delay=5, backoff=2, max_delay=60 * 3, logger=logging_logger)
|
|
34
|
-
def get_mq(self):
|
|
35
|
-
try:
|
|
36
|
-
if self.basepika.channel.is_closed:
|
|
37
|
-
logging_logger.info("重连中......")
|
|
38
|
-
self.re_conn()
|
|
39
|
-
logging_logger.info("重连完成......")
|
|
40
|
-
self.basepika.set_get_msg_callback(routing_key=self.queue, callback=self.callback, auto_ack=False)
|
|
41
|
-
self.basepika.start_get_msg()
|
|
42
|
-
except:
|
|
43
|
-
traceback.print_exc()
|
|
44
|
-
logging_logger.info("重连中......")
|
|
45
|
-
self.re_conn()
|
|
46
|
-
|
|
47
|
-
def callback(self, ch, method, properties, body):
|
|
48
|
-
# print(type(body))
|
|
49
|
-
# print(" [x] Received %r" % body)
|
|
50
|
-
# body = body.decode()
|
|
51
|
-
self.callback2(ch, method, properties, body)
|
|
52
|
-
if self.basepika.auto_ack is False:
|
|
53
|
-
self.basepika.basic_ack(ch, method)
|
|
54
|
-
|
|
55
|
-
def callback2(self, ch, method, properties, body):
|
|
56
|
-
pass
|
|
57
|
-
|
|
58
|
-
@retry(delay=5, backoff=2, max_delay=60 * 3, logger=logging_logger)
|
|
59
|
-
def send_mq(self, body, num=100):
|
|
60
|
-
try:
|
|
61
|
-
if self.basepika.get_queue_size(self.queue) < num:
|
|
62
|
-
self.basepika.easy_send_msg(routing_key=self.queue,
|
|
63
|
-
body=body,
|
|
64
|
-
properties=self.properties)
|
|
65
|
-
return True
|
|
66
|
-
else:
|
|
67
|
-
return False
|
|
68
|
-
except:
|
|
69
|
-
traceback.print_exc()
|
|
70
|
-
logging_logger.info("重连中......")
|
|
71
|
-
self.re_conn()
|
|
72
|
-
return False
|
|
73
|
-
|
|
74
|
-
def get_server_mq_num(self, num=100):
|
|
75
|
-
if self.basepika.get_queue_size(self.queue) < num:
|
|
76
|
-
return True
|
|
77
|
-
else:
|
|
78
|
-
return False
|
|
79
|
-
|
|
80
|
-
def easy_send_mq(self, body):
|
|
81
|
-
self.basepika.easy_send_msg(routing_key=self.queue,
|
|
82
|
-
body=body,
|
|
83
|
-
properties=self.properties)
|
|
1
|
+
import logging
|
|
2
|
+
import traceback
|
|
3
|
+
|
|
4
|
+
from re_common.v2.baselibrary.utils.basepika import BasePika
|
|
5
|
+
from retry import retry
|
|
6
|
+
|
|
7
|
+
logging_logger = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class UseMq(object):
|
|
11
|
+
|
|
12
|
+
def __init__(self, queue, qos=1):
|
|
13
|
+
self.queue = queue
|
|
14
|
+
self.qos = qos
|
|
15
|
+
self.basepika = BasePika()
|
|
16
|
+
self.basepika.set_default()
|
|
17
|
+
self.basepika.connect()
|
|
18
|
+
self.basepika.create_channel()
|
|
19
|
+
self.basepika.queue_declare(queue=queue, durable=True)
|
|
20
|
+
self.basepika.basic_qos(qos)
|
|
21
|
+
self.properties = self.basepika.get_properties()
|
|
22
|
+
|
|
23
|
+
def re_conn(self):
|
|
24
|
+
"""
|
|
25
|
+
重新连接
|
|
26
|
+
:return:
|
|
27
|
+
"""
|
|
28
|
+
self.basepika.connect()
|
|
29
|
+
self.basepika.create_channel()
|
|
30
|
+
self.basepika.queue_declare(queue=self.queue, durable=True)
|
|
31
|
+
self.basepika.basic_qos(self.qos)
|
|
32
|
+
|
|
33
|
+
@retry(delay=5, backoff=2, max_delay=60 * 3, logger=logging_logger)
|
|
34
|
+
def get_mq(self):
|
|
35
|
+
try:
|
|
36
|
+
if self.basepika.channel.is_closed:
|
|
37
|
+
logging_logger.info("重连中......")
|
|
38
|
+
self.re_conn()
|
|
39
|
+
logging_logger.info("重连完成......")
|
|
40
|
+
self.basepika.set_get_msg_callback(routing_key=self.queue, callback=self.callback, auto_ack=False)
|
|
41
|
+
self.basepika.start_get_msg()
|
|
42
|
+
except:
|
|
43
|
+
traceback.print_exc()
|
|
44
|
+
logging_logger.info("重连中......")
|
|
45
|
+
self.re_conn()
|
|
46
|
+
|
|
47
|
+
def callback(self, ch, method, properties, body):
|
|
48
|
+
# print(type(body))
|
|
49
|
+
# print(" [x] Received %r" % body)
|
|
50
|
+
# body = body.decode()
|
|
51
|
+
self.callback2(ch, method, properties, body)
|
|
52
|
+
if self.basepika.auto_ack is False:
|
|
53
|
+
self.basepika.basic_ack(ch, method)
|
|
54
|
+
|
|
55
|
+
def callback2(self, ch, method, properties, body):
|
|
56
|
+
pass
|
|
57
|
+
|
|
58
|
+
@retry(delay=5, backoff=2, max_delay=60 * 3, logger=logging_logger)
|
|
59
|
+
def send_mq(self, body, num=100):
|
|
60
|
+
try:
|
|
61
|
+
if self.basepika.get_queue_size(self.queue) < num:
|
|
62
|
+
self.basepika.easy_send_msg(routing_key=self.queue,
|
|
63
|
+
body=body,
|
|
64
|
+
properties=self.properties)
|
|
65
|
+
return True
|
|
66
|
+
else:
|
|
67
|
+
return False
|
|
68
|
+
except:
|
|
69
|
+
traceback.print_exc()
|
|
70
|
+
logging_logger.info("重连中......")
|
|
71
|
+
self.re_conn()
|
|
72
|
+
return False
|
|
73
|
+
|
|
74
|
+
def get_server_mq_num(self, num=100):
|
|
75
|
+
if self.basepika.get_queue_size(self.queue) < num:
|
|
76
|
+
return True
|
|
77
|
+
else:
|
|
78
|
+
return False
|
|
79
|
+
|
|
80
|
+
def easy_send_mq(self, body):
|
|
81
|
+
self.basepika.easy_send_msg(routing_key=self.queue,
|
|
82
|
+
body=body,
|
|
83
|
+
properties=self.properties)
|
|
@@ -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}")
|