pyxllib 0.3.96__py3-none-any.whl → 0.3.197__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.
- pyxllib/algo/geo.py +12 -0
- pyxllib/algo/intervals.py +1 -1
- pyxllib/algo/matcher.py +78 -0
- pyxllib/algo/pupil.py +187 -19
- pyxllib/algo/specialist.py +2 -1
- pyxllib/algo/stat.py +38 -2
- {pyxlpr → pyxllib/autogui}/__init__.py +1 -1
- pyxllib/autogui/activewin.py +246 -0
- pyxllib/autogui/all.py +9 -0
- pyxllib/{ext/autogui → autogui}/autogui.py +40 -11
- pyxllib/autogui/uiautolib.py +362 -0
- pyxllib/autogui/wechat.py +827 -0
- pyxllib/autogui/wechat_msg.py +421 -0
- pyxllib/autogui/wxautolib.py +84 -0
- pyxllib/cv/slidercaptcha.py +137 -0
- pyxllib/data/echarts.py +123 -12
- pyxllib/data/jsonlib.py +89 -0
- pyxllib/data/pglib.py +514 -30
- pyxllib/data/sqlite.py +231 -4
- pyxllib/ext/JLineViewer.py +14 -1
- pyxllib/ext/drissionlib.py +277 -0
- pyxllib/ext/kq5034lib.py +0 -1594
- pyxllib/ext/robustprocfile.py +497 -0
- pyxllib/ext/unixlib.py +6 -5
- pyxllib/ext/utools.py +108 -95
- pyxllib/ext/webhook.py +32 -14
- pyxllib/ext/wjxlib.py +88 -0
- pyxllib/ext/wpsapi.py +124 -0
- pyxllib/ext/xlwork.py +9 -0
- pyxllib/ext/yuquelib.py +1003 -71
- pyxllib/file/docxlib.py +1 -1
- pyxllib/file/libreoffice.py +165 -0
- pyxllib/file/movielib.py +9 -0
- pyxllib/file/packlib/__init__.py +112 -75
- pyxllib/file/pdflib.py +1 -1
- pyxllib/file/pupil.py +1 -1
- pyxllib/file/specialist/dirlib.py +1 -1
- pyxllib/file/specialist/download.py +10 -3
- pyxllib/file/specialist/filelib.py +266 -55
- pyxllib/file/xlsxlib.py +205 -50
- pyxllib/file/xlsyncfile.py +341 -0
- pyxllib/prog/cachetools.py +64 -0
- pyxllib/prog/filelock.py +42 -0
- pyxllib/prog/multiprogs.py +940 -0
- pyxllib/prog/newbie.py +9 -2
- pyxllib/prog/pupil.py +129 -60
- pyxllib/prog/specialist/__init__.py +176 -2
- pyxllib/prog/specialist/bc.py +5 -2
- pyxllib/prog/specialist/browser.py +11 -2
- pyxllib/prog/specialist/datetime.py +68 -0
- pyxllib/prog/specialist/tictoc.py +12 -13
- pyxllib/prog/specialist/xllog.py +5 -5
- pyxllib/prog/xlosenv.py +7 -0
- pyxllib/text/airscript.js +744 -0
- pyxllib/text/charclasslib.py +17 -5
- pyxllib/text/jiebalib.py +6 -3
- pyxllib/text/jinjalib.py +32 -0
- pyxllib/text/jsa_ai_prompt.md +271 -0
- pyxllib/text/jscode.py +159 -4
- pyxllib/text/nestenv.py +1 -1
- pyxllib/text/newbie.py +12 -0
- pyxllib/text/pupil/common.py +26 -0
- pyxllib/text/specialist/ptag.py +2 -2
- pyxllib/text/templates/echart_base.html +11 -0
- pyxllib/text/templates/highlight_code.html +17 -0
- pyxllib/text/templates/latex_editor.html +103 -0
- pyxllib/text/xmllib.py +76 -14
- pyxllib/xl.py +2 -1
- pyxllib-0.3.197.dist-info/METADATA +48 -0
- pyxllib-0.3.197.dist-info/RECORD +126 -0
- {pyxllib-0.3.96.dist-info → pyxllib-0.3.197.dist-info}/WHEEL +1 -2
- pyxllib/ext/autogui/__init__.py +0 -8
- pyxllib-0.3.96.dist-info/METADATA +0 -51
- pyxllib-0.3.96.dist-info/RECORD +0 -333
- pyxllib-0.3.96.dist-info/top_level.txt +0 -2
- pyxlpr/ai/__init__.py +0 -5
- pyxlpr/ai/clientlib.py +0 -1281
- pyxlpr/ai/specialist.py +0 -286
- pyxlpr/ai/torch_app.py +0 -172
- pyxlpr/ai/xlpaddle.py +0 -655
- pyxlpr/ai/xltorch.py +0 -705
- pyxlpr/data/__init__.py +0 -11
- pyxlpr/data/coco.py +0 -1325
- pyxlpr/data/datacls.py +0 -365
- pyxlpr/data/datasets.py +0 -200
- pyxlpr/data/gptlib.py +0 -1291
- pyxlpr/data/icdar/__init__.py +0 -96
- pyxlpr/data/icdar/deteval.py +0 -377
- pyxlpr/data/icdar/icdar2013.py +0 -341
- pyxlpr/data/icdar/iou.py +0 -340
- pyxlpr/data/icdar/rrc_evaluation_funcs_1_1.py +0 -463
- pyxlpr/data/imtextline.py +0 -473
- pyxlpr/data/labelme.py +0 -866
- pyxlpr/data/removeline.py +0 -179
- pyxlpr/data/specialist.py +0 -57
- pyxlpr/eval/__init__.py +0 -85
- pyxlpr/paddleocr.py +0 -776
- pyxlpr/ppocr/__init__.py +0 -15
- pyxlpr/ppocr/configs/rec/multi_language/generate_multi_language_configs.py +0 -226
- pyxlpr/ppocr/data/__init__.py +0 -135
- pyxlpr/ppocr/data/imaug/ColorJitter.py +0 -26
- pyxlpr/ppocr/data/imaug/__init__.py +0 -67
- pyxlpr/ppocr/data/imaug/copy_paste.py +0 -170
- pyxlpr/ppocr/data/imaug/east_process.py +0 -437
- pyxlpr/ppocr/data/imaug/gen_table_mask.py +0 -244
- pyxlpr/ppocr/data/imaug/iaa_augment.py +0 -114
- pyxlpr/ppocr/data/imaug/label_ops.py +0 -789
- pyxlpr/ppocr/data/imaug/make_border_map.py +0 -184
- pyxlpr/ppocr/data/imaug/make_pse_gt.py +0 -106
- pyxlpr/ppocr/data/imaug/make_shrink_map.py +0 -126
- pyxlpr/ppocr/data/imaug/operators.py +0 -433
- pyxlpr/ppocr/data/imaug/pg_process.py +0 -906
- pyxlpr/ppocr/data/imaug/randaugment.py +0 -143
- pyxlpr/ppocr/data/imaug/random_crop_data.py +0 -239
- pyxlpr/ppocr/data/imaug/rec_img_aug.py +0 -533
- pyxlpr/ppocr/data/imaug/sast_process.py +0 -777
- pyxlpr/ppocr/data/imaug/text_image_aug/__init__.py +0 -17
- pyxlpr/ppocr/data/imaug/text_image_aug/augment.py +0 -120
- pyxlpr/ppocr/data/imaug/text_image_aug/warp_mls.py +0 -168
- pyxlpr/ppocr/data/lmdb_dataset.py +0 -115
- pyxlpr/ppocr/data/pgnet_dataset.py +0 -104
- pyxlpr/ppocr/data/pubtab_dataset.py +0 -107
- pyxlpr/ppocr/data/simple_dataset.py +0 -372
- pyxlpr/ppocr/losses/__init__.py +0 -61
- pyxlpr/ppocr/losses/ace_loss.py +0 -52
- pyxlpr/ppocr/losses/basic_loss.py +0 -135
- pyxlpr/ppocr/losses/center_loss.py +0 -88
- pyxlpr/ppocr/losses/cls_loss.py +0 -30
- pyxlpr/ppocr/losses/combined_loss.py +0 -67
- pyxlpr/ppocr/losses/det_basic_loss.py +0 -208
- pyxlpr/ppocr/losses/det_db_loss.py +0 -80
- pyxlpr/ppocr/losses/det_east_loss.py +0 -63
- pyxlpr/ppocr/losses/det_pse_loss.py +0 -149
- pyxlpr/ppocr/losses/det_sast_loss.py +0 -121
- pyxlpr/ppocr/losses/distillation_loss.py +0 -272
- pyxlpr/ppocr/losses/e2e_pg_loss.py +0 -140
- pyxlpr/ppocr/losses/kie_sdmgr_loss.py +0 -113
- pyxlpr/ppocr/losses/rec_aster_loss.py +0 -99
- pyxlpr/ppocr/losses/rec_att_loss.py +0 -39
- pyxlpr/ppocr/losses/rec_ctc_loss.py +0 -44
- pyxlpr/ppocr/losses/rec_enhanced_ctc_loss.py +0 -70
- pyxlpr/ppocr/losses/rec_nrtr_loss.py +0 -30
- pyxlpr/ppocr/losses/rec_sar_loss.py +0 -28
- pyxlpr/ppocr/losses/rec_srn_loss.py +0 -47
- pyxlpr/ppocr/losses/table_att_loss.py +0 -109
- pyxlpr/ppocr/metrics/__init__.py +0 -44
- pyxlpr/ppocr/metrics/cls_metric.py +0 -45
- pyxlpr/ppocr/metrics/det_metric.py +0 -82
- pyxlpr/ppocr/metrics/distillation_metric.py +0 -73
- pyxlpr/ppocr/metrics/e2e_metric.py +0 -86
- pyxlpr/ppocr/metrics/eval_det_iou.py +0 -274
- pyxlpr/ppocr/metrics/kie_metric.py +0 -70
- pyxlpr/ppocr/metrics/rec_metric.py +0 -75
- pyxlpr/ppocr/metrics/table_metric.py +0 -50
- pyxlpr/ppocr/modeling/architectures/__init__.py +0 -32
- pyxlpr/ppocr/modeling/architectures/base_model.py +0 -88
- pyxlpr/ppocr/modeling/architectures/distillation_model.py +0 -60
- pyxlpr/ppocr/modeling/backbones/__init__.py +0 -54
- pyxlpr/ppocr/modeling/backbones/det_mobilenet_v3.py +0 -268
- pyxlpr/ppocr/modeling/backbones/det_resnet_vd.py +0 -246
- pyxlpr/ppocr/modeling/backbones/det_resnet_vd_sast.py +0 -285
- pyxlpr/ppocr/modeling/backbones/e2e_resnet_vd_pg.py +0 -265
- pyxlpr/ppocr/modeling/backbones/kie_unet_sdmgr.py +0 -186
- pyxlpr/ppocr/modeling/backbones/rec_mobilenet_v3.py +0 -138
- pyxlpr/ppocr/modeling/backbones/rec_mv1_enhance.py +0 -258
- pyxlpr/ppocr/modeling/backbones/rec_nrtr_mtb.py +0 -48
- pyxlpr/ppocr/modeling/backbones/rec_resnet_31.py +0 -210
- pyxlpr/ppocr/modeling/backbones/rec_resnet_aster.py +0 -143
- pyxlpr/ppocr/modeling/backbones/rec_resnet_fpn.py +0 -307
- pyxlpr/ppocr/modeling/backbones/rec_resnet_vd.py +0 -286
- pyxlpr/ppocr/modeling/heads/__init__.py +0 -54
- pyxlpr/ppocr/modeling/heads/cls_head.py +0 -52
- pyxlpr/ppocr/modeling/heads/det_db_head.py +0 -118
- pyxlpr/ppocr/modeling/heads/det_east_head.py +0 -121
- pyxlpr/ppocr/modeling/heads/det_pse_head.py +0 -37
- pyxlpr/ppocr/modeling/heads/det_sast_head.py +0 -128
- pyxlpr/ppocr/modeling/heads/e2e_pg_head.py +0 -253
- pyxlpr/ppocr/modeling/heads/kie_sdmgr_head.py +0 -206
- pyxlpr/ppocr/modeling/heads/multiheadAttention.py +0 -163
- pyxlpr/ppocr/modeling/heads/rec_aster_head.py +0 -393
- pyxlpr/ppocr/modeling/heads/rec_att_head.py +0 -202
- pyxlpr/ppocr/modeling/heads/rec_ctc_head.py +0 -88
- pyxlpr/ppocr/modeling/heads/rec_nrtr_head.py +0 -826
- pyxlpr/ppocr/modeling/heads/rec_sar_head.py +0 -402
- pyxlpr/ppocr/modeling/heads/rec_srn_head.py +0 -280
- pyxlpr/ppocr/modeling/heads/self_attention.py +0 -406
- pyxlpr/ppocr/modeling/heads/table_att_head.py +0 -246
- pyxlpr/ppocr/modeling/necks/__init__.py +0 -32
- pyxlpr/ppocr/modeling/necks/db_fpn.py +0 -111
- pyxlpr/ppocr/modeling/necks/east_fpn.py +0 -188
- pyxlpr/ppocr/modeling/necks/fpn.py +0 -138
- pyxlpr/ppocr/modeling/necks/pg_fpn.py +0 -314
- pyxlpr/ppocr/modeling/necks/rnn.py +0 -92
- pyxlpr/ppocr/modeling/necks/sast_fpn.py +0 -284
- pyxlpr/ppocr/modeling/necks/table_fpn.py +0 -110
- pyxlpr/ppocr/modeling/transforms/__init__.py +0 -28
- pyxlpr/ppocr/modeling/transforms/stn.py +0 -135
- pyxlpr/ppocr/modeling/transforms/tps.py +0 -308
- pyxlpr/ppocr/modeling/transforms/tps_spatial_transformer.py +0 -156
- pyxlpr/ppocr/optimizer/__init__.py +0 -61
- pyxlpr/ppocr/optimizer/learning_rate.py +0 -228
- pyxlpr/ppocr/optimizer/lr_scheduler.py +0 -49
- pyxlpr/ppocr/optimizer/optimizer.py +0 -160
- pyxlpr/ppocr/optimizer/regularizer.py +0 -52
- pyxlpr/ppocr/postprocess/__init__.py +0 -55
- pyxlpr/ppocr/postprocess/cls_postprocess.py +0 -33
- pyxlpr/ppocr/postprocess/db_postprocess.py +0 -234
- pyxlpr/ppocr/postprocess/east_postprocess.py +0 -143
- pyxlpr/ppocr/postprocess/locality_aware_nms.py +0 -200
- pyxlpr/ppocr/postprocess/pg_postprocess.py +0 -52
- pyxlpr/ppocr/postprocess/pse_postprocess/__init__.py +0 -15
- pyxlpr/ppocr/postprocess/pse_postprocess/pse/__init__.py +0 -29
- pyxlpr/ppocr/postprocess/pse_postprocess/pse/setup.py +0 -14
- pyxlpr/ppocr/postprocess/pse_postprocess/pse_postprocess.py +0 -118
- pyxlpr/ppocr/postprocess/rec_postprocess.py +0 -654
- pyxlpr/ppocr/postprocess/sast_postprocess.py +0 -355
- pyxlpr/ppocr/tools/__init__.py +0 -14
- pyxlpr/ppocr/tools/eval.py +0 -83
- pyxlpr/ppocr/tools/export_center.py +0 -77
- pyxlpr/ppocr/tools/export_model.py +0 -129
- pyxlpr/ppocr/tools/infer/predict_cls.py +0 -151
- pyxlpr/ppocr/tools/infer/predict_det.py +0 -300
- pyxlpr/ppocr/tools/infer/predict_e2e.py +0 -169
- pyxlpr/ppocr/tools/infer/predict_rec.py +0 -414
- pyxlpr/ppocr/tools/infer/predict_system.py +0 -204
- pyxlpr/ppocr/tools/infer/utility.py +0 -629
- pyxlpr/ppocr/tools/infer_cls.py +0 -83
- pyxlpr/ppocr/tools/infer_det.py +0 -134
- pyxlpr/ppocr/tools/infer_e2e.py +0 -122
- pyxlpr/ppocr/tools/infer_kie.py +0 -153
- pyxlpr/ppocr/tools/infer_rec.py +0 -146
- pyxlpr/ppocr/tools/infer_table.py +0 -107
- pyxlpr/ppocr/tools/program.py +0 -596
- pyxlpr/ppocr/tools/test_hubserving.py +0 -117
- pyxlpr/ppocr/tools/train.py +0 -163
- pyxlpr/ppocr/tools/xlprog.py +0 -748
- pyxlpr/ppocr/utils/EN_symbol_dict.txt +0 -94
- pyxlpr/ppocr/utils/__init__.py +0 -24
- pyxlpr/ppocr/utils/dict/ar_dict.txt +0 -117
- pyxlpr/ppocr/utils/dict/arabic_dict.txt +0 -162
- pyxlpr/ppocr/utils/dict/be_dict.txt +0 -145
- pyxlpr/ppocr/utils/dict/bg_dict.txt +0 -140
- pyxlpr/ppocr/utils/dict/chinese_cht_dict.txt +0 -8421
- pyxlpr/ppocr/utils/dict/cyrillic_dict.txt +0 -163
- pyxlpr/ppocr/utils/dict/devanagari_dict.txt +0 -167
- pyxlpr/ppocr/utils/dict/en_dict.txt +0 -63
- pyxlpr/ppocr/utils/dict/fa_dict.txt +0 -136
- pyxlpr/ppocr/utils/dict/french_dict.txt +0 -136
- pyxlpr/ppocr/utils/dict/german_dict.txt +0 -143
- pyxlpr/ppocr/utils/dict/hi_dict.txt +0 -162
- pyxlpr/ppocr/utils/dict/it_dict.txt +0 -118
- pyxlpr/ppocr/utils/dict/japan_dict.txt +0 -4399
- pyxlpr/ppocr/utils/dict/ka_dict.txt +0 -153
- pyxlpr/ppocr/utils/dict/korean_dict.txt +0 -3688
- pyxlpr/ppocr/utils/dict/latin_dict.txt +0 -185
- pyxlpr/ppocr/utils/dict/mr_dict.txt +0 -153
- pyxlpr/ppocr/utils/dict/ne_dict.txt +0 -153
- pyxlpr/ppocr/utils/dict/oc_dict.txt +0 -96
- pyxlpr/ppocr/utils/dict/pu_dict.txt +0 -130
- pyxlpr/ppocr/utils/dict/rs_dict.txt +0 -91
- pyxlpr/ppocr/utils/dict/rsc_dict.txt +0 -134
- pyxlpr/ppocr/utils/dict/ru_dict.txt +0 -125
- pyxlpr/ppocr/utils/dict/ta_dict.txt +0 -128
- pyxlpr/ppocr/utils/dict/table_dict.txt +0 -277
- pyxlpr/ppocr/utils/dict/table_structure_dict.txt +0 -2759
- pyxlpr/ppocr/utils/dict/te_dict.txt +0 -151
- pyxlpr/ppocr/utils/dict/ug_dict.txt +0 -114
- pyxlpr/ppocr/utils/dict/uk_dict.txt +0 -142
- pyxlpr/ppocr/utils/dict/ur_dict.txt +0 -137
- pyxlpr/ppocr/utils/dict/xi_dict.txt +0 -110
- pyxlpr/ppocr/utils/dict90.txt +0 -90
- pyxlpr/ppocr/utils/e2e_metric/Deteval.py +0 -574
- pyxlpr/ppocr/utils/e2e_metric/polygon_fast.py +0 -83
- pyxlpr/ppocr/utils/e2e_utils/extract_batchsize.py +0 -87
- pyxlpr/ppocr/utils/e2e_utils/extract_textpoint_fast.py +0 -457
- pyxlpr/ppocr/utils/e2e_utils/extract_textpoint_slow.py +0 -592
- pyxlpr/ppocr/utils/e2e_utils/pgnet_pp_utils.py +0 -162
- pyxlpr/ppocr/utils/e2e_utils/visual.py +0 -162
- pyxlpr/ppocr/utils/en_dict.txt +0 -95
- pyxlpr/ppocr/utils/gen_label.py +0 -81
- pyxlpr/ppocr/utils/ic15_dict.txt +0 -36
- pyxlpr/ppocr/utils/iou.py +0 -54
- pyxlpr/ppocr/utils/logging.py +0 -69
- pyxlpr/ppocr/utils/network.py +0 -84
- pyxlpr/ppocr/utils/ppocr_keys_v1.txt +0 -6623
- pyxlpr/ppocr/utils/profiler.py +0 -110
- pyxlpr/ppocr/utils/save_load.py +0 -150
- pyxlpr/ppocr/utils/stats.py +0 -72
- pyxlpr/ppocr/utils/utility.py +0 -80
- pyxlpr/ppstructure/__init__.py +0 -13
- pyxlpr/ppstructure/predict_system.py +0 -187
- pyxlpr/ppstructure/table/__init__.py +0 -13
- pyxlpr/ppstructure/table/eval_table.py +0 -72
- pyxlpr/ppstructure/table/matcher.py +0 -192
- pyxlpr/ppstructure/table/predict_structure.py +0 -136
- pyxlpr/ppstructure/table/predict_table.py +0 -221
- pyxlpr/ppstructure/table/table_metric/__init__.py +0 -16
- pyxlpr/ppstructure/table/table_metric/parallel.py +0 -51
- pyxlpr/ppstructure/table/table_metric/table_metric.py +0 -247
- pyxlpr/ppstructure/table/tablepyxl/__init__.py +0 -13
- pyxlpr/ppstructure/table/tablepyxl/style.py +0 -283
- pyxlpr/ppstructure/table/tablepyxl/tablepyxl.py +0 -118
- pyxlpr/ppstructure/utility.py +0 -71
- pyxlpr/xlai.py +0 -10
- /pyxllib/{ext/autogui → autogui}/virtualkey.py +0 -0
- {pyxllib-0.3.96.dist-info → pyxllib-0.3.197.dist-info/licenses}/LICENSE +0 -0
pyxllib/text/charclasslib.py
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
# -*- coding: utf-8 -*-
|
3
3
|
# @Author : 陈坤泽
|
4
4
|
# @Email : 877362867@qq.com
|
5
|
+
# @Date : 2023/12/29
|
5
6
|
|
6
7
|
"""
|
7
8
|
字符分类
|
@@ -67,8 +68,11 @@ def get_charclass_num(content):
|
|
67
68
|
return ct2
|
68
69
|
|
69
70
|
|
70
|
-
def get_charclass_rate(content):
|
71
|
-
""" 检查字符类型分布数量
|
71
|
+
def get_charclass_rate(content, round_digits=4):
|
72
|
+
""" 检查字符类型分布数量
|
73
|
+
|
74
|
+
:param str content: 文本内容
|
75
|
+
"""
|
72
76
|
ct = get_charclass_num(content)
|
73
77
|
|
74
78
|
# 这一类权重要翻倍
|
@@ -80,12 +84,20 @@ def get_charclass_rate(content):
|
|
80
84
|
ct2 = Counter()
|
81
85
|
for k, v in ct.most_common():
|
82
86
|
ct2[k] = v / total
|
87
|
+
if round_digits is not None:
|
88
|
+
ct2[k] = round(ct2[k], round_digits)
|
83
89
|
return ct2
|
84
90
|
|
85
91
|
|
86
92
|
def check_language_from_counter(ct):
|
87
|
-
""" 检查语言类型
|
88
|
-
|
93
|
+
""" 检查语言类型
|
94
|
+
|
95
|
+
todo 这里的规则应该还可以再优化,以及不同的业务场景,这些规则应该也要再调整
|
96
|
+
这个比例最早是给表格设计的,表格很可能表头是中文,中间都是英文、数字数据,此时仍然归为中文
|
97
|
+
但如果是一般性的文档,可能要提高中文的比例,才能视为中文文档
|
98
|
+
"""
|
99
|
+
ct['常用汉字'] = ct.get('常用汉字', 0)
|
100
|
+
ct['偏僻汉字'] = ct.get('偏僻汉字', 0)
|
89
101
|
|
90
102
|
if '繁体汉字' in ct:
|
91
103
|
if safe_div(ct['繁体汉字'], ct['常用汉字']) > 0.1:
|
@@ -95,7 +107,7 @@ def check_language_from_counter(ct):
|
|
95
107
|
return '中文'
|
96
108
|
|
97
109
|
if '其他字符' in ct:
|
98
|
-
if ct['其他字符']
|
110
|
+
if safe_div(ct['其他字符'], ct['字母']) > 0.1:
|
99
111
|
return '其他'
|
100
112
|
|
101
113
|
if '字母' in ct:
|
pyxllib/text/jiebalib.py
CHANGED
@@ -14,6 +14,7 @@ import pandas as pd
|
|
14
14
|
|
15
15
|
import jieba
|
16
16
|
import jieba.posseg as pseg
|
17
|
+
from simhash import Simhash
|
17
18
|
|
18
19
|
from pyxllib.prog.pupil import DictTool, run_once
|
19
20
|
from pyxllib.file.specialist import XlPath
|
@@ -163,14 +164,16 @@ class TextClassifier:
|
|
163
164
|
|
164
165
|
return ct
|
165
166
|
|
166
|
-
def compute_tfidf(self, outfile=None, sheet_name='tf-idf', normalize=False, function_word_weight=0.2,
|
167
|
+
def compute_tfidf(self, outfile=None, sheet_name='tf-idf', normalize=False, function_word_weight=0.2,
|
168
|
+
add_flag=False):
|
167
169
|
""" 重算tfidf表 """
|
168
170
|
from math import log10
|
169
171
|
|
170
172
|
# 1 统计频数和出现该词的文章数
|
171
173
|
d = dict()
|
172
174
|
for text in tqdm(self.texts, '词频统计'):
|
173
|
-
ct = self.get_text_tf(text, normalize=normalize, function_word_weight=function_word_weight,
|
175
|
+
ct = self.get_text_tf(text, normalize=normalize, function_word_weight=function_word_weight,
|
176
|
+
add_flag=add_flag)
|
174
177
|
for k, v in ct.items():
|
175
178
|
if k not in d:
|
176
179
|
d[k] = [0, 0]
|
@@ -247,7 +250,7 @@ class TextClassifier:
|
|
247
250
|
return sims[:maxn]
|
248
251
|
|
249
252
|
def refine_vecs(self):
|
250
|
-
"""
|
253
|
+
""" 优化向量数据,去掉权重小余0.0001的维度 """
|
251
254
|
# 1 计算每个向量的长度
|
252
255
|
vecs = []
|
253
256
|
for vec in tqdm(self.vecs, '优化向量'):
|
pyxllib/text/jinjalib.py
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# @Author : 陈坤泽
|
4
|
+
# @Email : 877362867@qq.com
|
5
|
+
# @Date : 2024/05/26
|
6
|
+
|
7
|
+
from pyxllib.prog.pupil import check_install_package
|
8
|
+
|
9
|
+
# 一个xpath解析库
|
10
|
+
check_install_package('jinja2')
|
11
|
+
|
12
|
+
import jinja2
|
13
|
+
from jinja2 import Template, Environment
|
14
|
+
|
15
|
+
from pyxllib.file.specialist import XlPath
|
16
|
+
|
17
|
+
|
18
|
+
def set_template(s, *args, **kwargs):
|
19
|
+
""" todo 这个名字会不会太容易冲突了? """
|
20
|
+
return Template(s.strip(), *args, **kwargs)
|
21
|
+
|
22
|
+
|
23
|
+
def set_meta_template(s, meta_start='[[', meta_end=']]', **kwargs):
|
24
|
+
""" 支持预先用某些格式渲染后,再返回标准渲染模板 """
|
25
|
+
t = Template(s.strip(), variable_start_string=meta_start,
|
26
|
+
variable_end_string=meta_end).render(**kwargs)
|
27
|
+
return Template(t)
|
28
|
+
|
29
|
+
|
30
|
+
def get_jinja_template(name, **kwargs):
|
31
|
+
template = Environment(**kwargs).from_string((XlPath(__file__).parent / f'templates/{name}').read_text())
|
32
|
+
return template
|
@@ -0,0 +1,271 @@
|
|
1
|
+
# 1 任务大纲
|
2
|
+
1. 我们是"未来社"社团,我是社长code4101,负责设计你们AI社员们的提示词,用来处理来自USER的任务需求。
|
3
|
+
2. USER有多种可能的角色:社长,其他社员,社团外的成员。
|
4
|
+
3. 你是社团中"JSA组"的组长,协助JSA相关问题的专业处理。
|
5
|
+
|
6
|
+
# 2 JSA简介
|
7
|
+
|
8
|
+
1. wps办公在Javascript语言基础上,设计了一个叫jsa的编程语言,语法接口跟vba类似。
|
9
|
+
2. 其实比较适合、需要用到编程的,也就Excel等表格场景,USER大部分问题都是跟表格相关的。
|
10
|
+
3. wps的在线表格里,也称jsa为"AirScript",或者简称as。
|
11
|
+
4. 近期官网从jsa1.0更新到了jsa2.0版本,它们有些细微的区别。
|
12
|
+
5. 你在涉及到提供jsa代码时,注意变量命名默认用尽量简洁的英文名,注释用中文,具体命名可以参考后文会给到的一些代码示例,写法风格。默认不写每句末尾的分号。
|
13
|
+
|
14
|
+
# 3 常用工具介绍
|
15
|
+
|
16
|
+
1. jsa本身那套vba风格功能,用来处理表格的一些复杂问题时,不够方便,所以我在平时使用中,封装积累了一些工具,这些工具函数都是你可以直接使用的。
|
17
|
+
2. 为了篇幅简洁,部分函数给到的实现内容是空的,不是代表没有实现或没有功能,而是我这里省略掉了细节。
|
18
|
+
3. 部分更细节的东西,或其他函数工具,USER会在具体聊天中再根据需要给到你,这里列出的都是我认为相对比较重要,常用的功能,以及你也可以通过这里的实现看出跟vba的相似性,更好掌握jsa的用法。
|
19
|
+
|
20
|
+
## 3.1 定位操作
|
21
|
+
|
22
|
+
```js
|
23
|
+
/**
|
24
|
+
* @param what 要查找的内容
|
25
|
+
* @param ur 查找区域,默认当前表格UsedRange
|
26
|
+
* @param lookAt 可以选xlWhole(单元格内容=what)或xlPart(单元格内容包含了what)
|
27
|
+
* @return 找到的单元格
|
28
|
+
*/
|
29
|
+
function findCel(what, ur = ActiveSheet.UsedRange, lookAt = xlWhole) {
|
30
|
+
return ur.Find(what, undefined, undefined, lookAt)
|
31
|
+
}
|
32
|
+
|
33
|
+
function findRow(what, ur = ActiveSheet.UsedRange, lookAt = xlWhole) {}
|
34
|
+
|
35
|
+
function findCol(what, ur = ActiveSheet.UsedRange, lookAt = xlWhole) {
|
36
|
+
let cel = findCel(what, ur, lookAt)
|
37
|
+
if (cel) return cel.Column
|
38
|
+
}
|
39
|
+
|
40
|
+
// 判断 cells 集合是否全空
|
41
|
+
function isEmpty(cels) {}
|
42
|
+
|
43
|
+
// 获取ws实际使用的区域:会裁剪掉四周没有数据的空白区域
|
44
|
+
function getUsedRange(ws = ActiveSheet) {}
|
45
|
+
|
46
|
+
/**
|
47
|
+
* 表格结构化定位工具
|
48
|
+
* @param sheet 输入表格名,或表格对象
|
49
|
+
* @param dataRow 输入两个值的数组,第1个值标记(不含表头的)数据起始行,第2个值标记数据结束行。
|
50
|
+
* 只输入单数值,未传入第2个参数时,默认以0填充,例如:4 -> [4, 0]
|
51
|
+
* 起始行标记:
|
52
|
+
* 0,智能检测。如果cols有给入字段名,以找到的第1个字段的下一行作为起始行。否则默认设置为ur的第2行。
|
53
|
+
* 正整数,人工精确指定数据起始行(输入的是整张表格的绝对行号)
|
54
|
+
* '料理'等精确的字段名标记,以找到的单元格下一行作为数据起始行
|
55
|
+
* 负数,比如-2,表示基于第2列(B列),使用.End(xlDown)机制找到第1条有数据的行的下一行作为数据起始行
|
56
|
+
* 结束行标记:
|
57
|
+
* 0,智能检测。以getUsedRange的最后一行为准。
|
58
|
+
* 正整数,人工精确指定数据结束行(有时候数据实际可能有100行,可以只写10,实现少量部分样本的功能测试)
|
59
|
+
* '料理'等精确的字段名标记,同负数模式,以找到的所在列,配合.End(xlUp)确定最后一行有数据的位置
|
60
|
+
* 负数,比如-3,表示基于第3列(C列),使用.End(xlUp)对这列的最后一行数据位置做判定,作为数据最后一行的标记
|
61
|
+
* @param colNames 后续要使用到的相关字段数据,使用as2.0版本的时候,该参数可以不输入,会在使用中动态检索
|
62
|
+
* @return [ur, rows, cols]
|
63
|
+
* ur,表格实际的UsedRange
|
64
|
+
* rows是字典,rows.start、rows.end分别存储了数据的起止行
|
65
|
+
* cols也是字典,存储了个字段名对应的所在列编号,比如cols['料理']
|
66
|
+
* 注:返回的行、列,都是相对ur的位置,所以可以类似这样 ur.Cells(rows.start, cols[x]) 取到第1条数据在x字段的值
|
67
|
+
*/
|
68
|
+
function locateTableRange(sheet, dataRow = [0, 0], colNames = []) {}
|
69
|
+
|
70
|
+
/**
|
71
|
+
* 表格结构化定位工具的增强版本,在locateTableRange基础上增加了tools简化一些常用操作
|
72
|
+
* @returns {Array} [ur, rows, cols, tools]
|
73
|
+
* tools提供了如下便捷接口:
|
74
|
+
* getcel(row, colName): 获取指定行列的单元格
|
75
|
+
* getval(row, colName): 获取指定行列的单元格.Value2值
|
76
|
+
* getval(row, colName): 获取指定行列的单元格.Text值
|
77
|
+
* findargcel(argName, direction): 查找参数单元格及其关联值
|
78
|
+
* direction可选'down'(下方)或'right'(右侧),默认为'down'
|
79
|
+
*/
|
80
|
+
function locateTableRange2(sheetName, dataRow = [0, 0], colNames = []) {}
|
81
|
+
```
|
82
|
+
|
83
|
+
这里最关键的是locateTableRange函数,这个函数的实现用到了前面的那些函数。
|
84
|
+
用这个函数可以方便地进行各种表格定位操作。
|
85
|
+
|
86
|
+
注意这里locateTableRange2仅能在jsa2.0中使用。
|
87
|
+
|
88
|
+
## 3.2 数据批量导入导出
|
89
|
+
|
90
|
+
```js
|
91
|
+
// 打包sheet下多个字段fields的数据
|
92
|
+
// 使用示例:packTableDataFields('料理', ['名称', '标签']
|
93
|
+
// fields的参数支持字段名称或整数,明确指定某列的位置
|
94
|
+
// 返回格式:{'名称': [x1, x2, ...], '标签': [y1, y2, ...]}
|
95
|
+
function packTableDataFields(sheetName, fields, dataRow = [0, 0], filterEmptyRows = true) {}
|
96
|
+
|
97
|
+
function clearSheetData(headerRow = 1, dataStartRow = 2, sheet = ActiveSheet) {}
|
98
|
+
|
99
|
+
// 将py里df.to_dict(orient='split')的数据格式写入sheet
|
100
|
+
// 这个数据一般有3个属性:index, columns, data
|
101
|
+
function writeDfSplitDictToSheet(jsonData, headerRow = 1, dataStartRow = 2, sheet = ActiveSheet) {}
|
102
|
+
|
103
|
+
function writeArrToSheet(arr, startCel) {}
|
104
|
+
|
105
|
+
// 这个相比writeDfSplitDictToSheet全量覆盖协助,是专门用来插入新的数据进行增量更新的
|
106
|
+
function insertNewDataWithHeaders(jsonData, headerRow = 1, dataStartRow = 2, sheet = ActiveSheet) {}
|
107
|
+
```
|
108
|
+
|
109
|
+
## 3.3 调用后端python服务
|
110
|
+
|
111
|
+
我的服务器是有很多电脑的,比如codepc_mi15专门用来处理"考勤"相关任务。
|
112
|
+
还有codepc_aw、titan2机器等。
|
113
|
+
|
114
|
+
jsa里是可以联网去调用我这里的python后端服务的,我一般简称jsa-py。
|
115
|
+
也可以反过来,py-jsa就是指在py去调用jsa,但py-jsa只能使用jsa1.0版本,不支持高级的jsa2.0。
|
116
|
+
所以py-jsa,jsa1.0的场景无法使用locateTableRange2、tools相关功能。
|
117
|
+
|
118
|
+
```js
|
119
|
+
// 保留环境状态,运行短小任务,返回代码中print输出的内容
|
120
|
+
function runPyScript(script, query = '', host = '{{JSA_POST_DEFAULT_HOST}}') {}
|
121
|
+
|
122
|
+
// 每次都是独立环境状态,运行较长时间任务,返回代码中return的字典数据
|
123
|
+
function runIsolatedPyScript(script, host = '{{JSA_POST_DEFAULT_HOST}}') {}
|
124
|
+
function getPyTaskResult(taskId, retries = 1, host = '{{JSA_POST_DEFAULT_HOST}}', delay = 5000) {}
|
125
|
+
```
|
126
|
+
|
127
|
+
# 4 一些常见问题的示例代码
|
128
|
+
|
129
|
+
(这里的示例想了下还是尽量写完善些好,但后续需要机制进行分流处理,都交一个节点操作有些麻烦)
|
130
|
+
|
131
|
+
示例1:jsa调用py,在每一行匹配用户id
|
132
|
+
```js
|
133
|
+
// 遍历表格,每一行运行runPyScript来从后端取到结果
|
134
|
+
function 更新匹配() {
|
135
|
+
const [ur, rows, cols] = locateTableRange('报名表', 4)
|
136
|
+
|
137
|
+
function getval(i, j) {
|
138
|
+
return ur.Cells(i, cols[j]).Text
|
139
|
+
}
|
140
|
+
|
141
|
+
for (let i = rows.start; i <= rows.end; i++) {
|
142
|
+
if (ur.Cells(i, cols['用户ID']).Text) continue
|
143
|
+
pyScript = `
|
144
|
+
from xlsln.kq5034.ckz240412网课考勤 import 查找用户
|
145
|
+
res = 查找用户(['${getval(i, '真实姓名')}', '${getval(i, '微信昵称')}'],
|
146
|
+
['${getval(i, '手机号')}', '${getval(i, '错误手机号')}'],
|
147
|
+
参考课程名='第29届觉观技术公益网课', shop_id=1, return_mode=1)
|
148
|
+
print(res)
|
149
|
+
`
|
150
|
+
const text = runPyScript(pyScript)
|
151
|
+
const matches = text.match(/\('([^']*)', (\d+)\)/)
|
152
|
+
if (matches) {
|
153
|
+
ur.Cells(i, cols['用户ID']).Value2 = matches[1]
|
154
|
+
ur.Cells(i, cols['匹配得分']).Value2 = matches[2]
|
155
|
+
}
|
156
|
+
}
|
157
|
+
}
|
158
|
+
```
|
159
|
+
|
160
|
+
生成代码的时候注意,我大部分表格数据都是从第4行开始,第1行写合并单元格大标题,第2行写具体字段名,第3行写字段的注释。
|
161
|
+
或者前3行用来放配置选项,功能数据等从第4行开始展示。
|
162
|
+
|
163
|
+
以及大部分功能,都是要封装成函数来供应的,工具性的函数写英文命名,业务性的函数可以写中文名。
|
164
|
+
|
165
|
+
示例2:
|
166
|
+
(1)jsa调用py,获得问卷星增量数据
|
167
|
+
(2)将py中的df数据增量写入表格
|
168
|
+
```js
|
169
|
+
const maxValue = Math.max(
|
170
|
+
0, // 默认值
|
171
|
+
...packTableDataFields('问卷星', ['序号'], 4)['序号']
|
172
|
+
.filter(value => typeof value === 'number')
|
173
|
+
)
|
174
|
+
const pyScript = `
|
175
|
+
from xlsln.kq5034.ckz240412网课考勤 import 获得问卷星数据
|
176
|
+
exist_max_id = ${maxValue} # 已有数据的最大id
|
177
|
+
df = 获得问卷星数据()
|
178
|
+
if min(df['序号']) > exist_max_id: # 如果第一页数据不全,直接更新下载全量数据
|
179
|
+
df = 获得问卷星数据(True)
|
180
|
+
df = df[df['序号'] > exist_max_id] # 过滤出新数据
|
181
|
+
data = df.to_dict(orient='split') # 返回数据
|
182
|
+
del data['index']
|
183
|
+
return data
|
184
|
+
`
|
185
|
+
const jsonData = runIsolatedPyScript(pyScript, 'codepc_mi15')
|
186
|
+
// formatLocalDatetime是我自定义的一个获得当期本地时间的函数
|
187
|
+
Range('B3').Value2 = '最近运行更新时间:\n' + formatLocalDatetime()
|
188
|
+
insertNewDataWithHeaders(jsonData, 2, 4)
|
189
|
+
```
|
190
|
+
|
191
|
+
示例3:
|
192
|
+
(1)对一些需要运行很长时间的任务,一般需要一个配置单元格,比如这里是'E3'。
|
193
|
+
如果E3为空,则启动程序,并且注意runIsolatedPyScript传参要给出long_task: true。
|
194
|
+
(2)然后在E3记录task_id,还可以在F3做备注。 如果E3不为空,则去检查程序是否运行完了。
|
195
|
+
|
196
|
+
```js
|
197
|
+
if (isEmpty(Range('E3'))) {
|
198
|
+
const dataForPy = packTableDataFields(ActiveSheet, [1], 4)[1]
|
199
|
+
const pyScript = `
|
200
|
+
import json
|
201
|
+
from xlsln.kq5034.ckz240412网课考勤 import Kq5034
|
202
|
+
data = json.loads(r"""${JSON.stringify(dataForPy)}""")
|
203
|
+
Kq5034().update_shop1_all_lesson_playback_settings(data)
|
204
|
+
return {'res': '更新完成'}
|
205
|
+
`
|
206
|
+
const res = runIsolatedPyScript({script: pyScript, long_task: true}, 'codepc_mi15')
|
207
|
+
Range('E3').Value2 = res['task_id']
|
208
|
+
Range('F3').Value2 = `已启动程序,程序id见E3`
|
209
|
+
} else {
|
210
|
+
taskId = Range('E3').Value2
|
211
|
+
Range('F3').Value2 = taskId + getPyTaskResult(taskId)['res']
|
212
|
+
Range('E3').Value2 = ''
|
213
|
+
}
|
214
|
+
```
|
215
|
+
|
216
|
+
示例4:tools.getval用途
|
217
|
+
|
218
|
+
1. 表格布局
|
219
|
+
A1: '商品名' B1: '价格'
|
220
|
+
A2: '苹果' B2: 5
|
221
|
+
A3: '香蕉' B3: 3
|
222
|
+
|
223
|
+
2. 代码对比
|
224
|
+
```js
|
225
|
+
// jsa1.0 传统写法
|
226
|
+
const [ur, rows, cols] = locateTableRange('商品表', 4)
|
227
|
+
ur.Cells(2, cols['价格']).Value2 // 5
|
228
|
+
ur.Cells(3, cols['价格']).Value2 // 3
|
229
|
+
|
230
|
+
// jsa2.0 tools.findargcel自动处理了相邻单元格的定位,让配置项读取更加优雅
|
231
|
+
const [ur, rows, cols, tools] = locateTableRange2('商品表', 4)
|
232
|
+
tools.getval(2, '价格')
|
233
|
+
tools.getval(3, '价格')
|
234
|
+
```
|
235
|
+
|
236
|
+
示例5:tools.findargcel用途
|
237
|
+
|
238
|
+
1. 表格布局
|
239
|
+
A1: '用户名:' A2: '张三'
|
240
|
+
B1: '密码:' B2: '123456'
|
241
|
+
|
242
|
+
2. 代码对比
|
243
|
+
```js
|
244
|
+
// 传统写法
|
245
|
+
const [ur, rows, cols] = locateTableRange('配置表', 4)
|
246
|
+
findCel('用户名:', ur).Offset(1, 0).Text
|
247
|
+
findCel('密码:', ur).Offset(1, 0).Text
|
248
|
+
|
249
|
+
// tools写法
|
250
|
+
const [ur, rows, cols, tools] = locateTableRange2('配置表', 4)
|
251
|
+
tools.findargcel('用户名:').Text
|
252
|
+
tools.findargcel('密码:').Text
|
253
|
+
```
|
254
|
+
|
255
|
+
示例6: py-jsa用法
|
256
|
+
除了在jsa里调用py,有时候可能要反过来py调用jsa,此时写法风格类似如下:
|
257
|
+
|
258
|
+
```py
|
259
|
+
from pyxllib.ext.wpsapi2 import WpsOnlineWorkbook, WpsOnlineScriptApi
|
260
|
+
|
261
|
+
# 1 方案1:运行jsa现有脚本的方式,这种可以支持现有的写好的jsa2代码
|
262
|
+
wb2 = WpsOnlineScriptApi('file_id', 'script_id')
|
263
|
+
# content_argv的字典,到jsa后,可以类似这样取到值Context.argv.funcName
|
264
|
+
wb2.run_script2('sum', 1, 2, 3) # 第1个参数是要调用的jsa函数名,后面则是*args各位置参数值
|
265
|
+
|
266
|
+
# 2 方案2:直接提供代码的方式,只能支持jsa1
|
267
|
+
wb = WpsOnlineWorkbook('file_id')
|
268
|
+
wb.run_airscript("return 'ok'")
|
269
|
+
```
|
270
|
+
|
271
|
+
注意py-jsa,是指jsa里不会再需要调用py的部分了,jsa-py则是py里不会再有调用jsa的部分,否则就循环引用了。
|
pyxllib/text/jscode.py
CHANGED
@@ -7,12 +7,18 @@
|
|
7
7
|
from collections import Counter
|
8
8
|
import re
|
9
9
|
import textwrap
|
10
|
+
import os
|
11
|
+
|
12
|
+
from jinja2 import Template
|
10
13
|
|
11
14
|
try:
|
12
15
|
import jsbeautifier
|
13
16
|
except ModuleNotFoundError:
|
14
17
|
pass
|
15
18
|
|
19
|
+
from pyxllib.file.specialist import XlPath
|
20
|
+
from pyxllib.prog.cachetools import xlcache
|
21
|
+
|
16
22
|
|
17
23
|
def __1_删注释功能():
|
18
24
|
"""
|
@@ -90,7 +96,7 @@ def 回溯区分正则除号(c):
|
|
90
96
|
return True # 正则
|
91
97
|
|
92
98
|
|
93
|
-
class JSParser
|
99
|
+
class JSParser:
|
94
100
|
def 普通引号(self, 号='"'): # 号:开始结束定界符,下同
|
95
101
|
while self.indexPointer < self.jsCodeLength: # 正常会提前 return 见下
|
96
102
|
self.indexPointer += 1
|
@@ -264,6 +270,13 @@ def remove_js_comments(jsSourceCode): # 对外接口,将本来用得两行代
|
|
264
270
|
|
265
271
|
|
266
272
|
def __2_类js的as处理功能():
|
273
|
+
"""
|
274
|
+
|
275
|
+
250306周四15:23,airscript_head应该是旧版的jsa工具代码。
|
276
|
+
而get_airscript_head2应该是获得新版jsa工具代码的函数接口。
|
277
|
+
|
278
|
+
:return:
|
279
|
+
"""
|
267
280
|
pass
|
268
281
|
|
269
282
|
|
@@ -436,6 +449,27 @@ function isNextMonth(date) {
|
|
436
449
|
""".strip()
|
437
450
|
|
438
451
|
|
452
|
+
@xlcache()
|
453
|
+
def get_airscript_head2(definitions=False):
|
454
|
+
""" 原始airscript.js并不是能直接全部运行的代码,里面有些占位变量要替换掉
|
455
|
+
|
456
|
+
:param bool definitions:
|
457
|
+
False: 正常填充变量后,返回全部代码
|
458
|
+
True: 填充后,拆分成一个个函数定义的字典返回
|
459
|
+
:return:
|
460
|
+
"""
|
461
|
+
s = (XlPath(__file__).parent / 'airscript.js').read_text().strip()
|
462
|
+
vars = {
|
463
|
+
'JSA_POST_HOST_URL': os.getenv('JSA_POST_HOST_URL'),
|
464
|
+
'JSA_POST_TOKEN': os.getenv('JSA_POST_TOKEN'),
|
465
|
+
'JSA_POST_DEFAULT_HOST': os.getenv('JSA_POST_DEFAULT_HOST'),
|
466
|
+
}
|
467
|
+
content = Template(s).render(vars)
|
468
|
+
if not definitions:
|
469
|
+
return content
|
470
|
+
return extract_definitions_with_comments(content + '\n')
|
471
|
+
|
472
|
+
|
439
473
|
class AirScriptCodeFixer:
|
440
474
|
@classmethod
|
441
475
|
def fix_colors(cls, code_text):
|
@@ -558,7 +592,8 @@ class AirScriptCodeFixer:
|
|
558
592
|
包括代码美化,默认缩进是4,但在训练阶段,建议默认缩进是2,
|
559
593
|
"""
|
560
594
|
# 1 代码精简
|
561
|
-
code_text = re.sub(r'Application\.(WorksheetFunction|ActiveWorkbook|ActiveSheet|Sheets|Range|Workbook)', r'\1',
|
595
|
+
code_text = re.sub(r'Application\.(WorksheetFunction|ActiveWorkbook|ActiveSheet|Sheets|Range|Workbook)', r'\1',
|
596
|
+
code_text)
|
562
597
|
code_text = re.sub(r'Workbook\.(Sheets)', r'\1', code_text)
|
563
598
|
code_text = re.sub(r'ActiveSheet\.(Range|Rows|Columns|Cells)', r'\1', code_text)
|
564
599
|
code_text = re.sub(r'(\w+)\.(Row|Column)\s*\+\s*\1\.\2s\.Count\s*-\s*1', r'\1.\2End', code_text)
|
@@ -646,7 +681,8 @@ class AirScriptCodeFixer:
|
|
646
681
|
def remove_stdcode(cls, code_text):
|
647
682
|
""" 删除开头固定的组件头代码 """
|
648
683
|
code_text = re.sub(r'(.*?)(//\s*1[\.\s]+定位)', r'\2', code_text, flags=re.DOTALL)
|
649
|
-
code_text = re.sub(r'// 0 基础组件代码(可以放在功能代码之前,也能放在最后面).+?$', '', code_text,
|
684
|
+
code_text = re.sub(r'// 0 基础组件代码(可以放在功能代码之前,也能放在最后面).+?$', '', code_text,
|
685
|
+
flags=re.DOTALL)
|
650
686
|
return 1, code_text
|
651
687
|
|
652
688
|
@classmethod
|
@@ -763,5 +799,124 @@ class AirScriptCodeFixer:
|
|
763
799
|
return 1, js_code2
|
764
800
|
|
765
801
|
|
766
|
-
|
802
|
+
def __3_js代码结构解析():
|
767
803
|
pass
|
804
|
+
|
805
|
+
|
806
|
+
def extract_definitions_with_comments(js_code):
|
807
|
+
""" 找出、切分每段函数的定义(包含函数开头的注释)
|
808
|
+
|
809
|
+
这里是用正则实现的版本,强制要求函数结束的时候用的是单行}结尾
|
810
|
+
如果实现中间内容也会出现这种单行}结尾,可以想写特殊手段规避开
|
811
|
+
"""
|
812
|
+
pattern = r"""
|
813
|
+
# 第1组:前缀注释
|
814
|
+
( (?:(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)|(?://[^\n]*))\s* )*
|
815
|
+
# 第2组:声明部分
|
816
|
+
( \b(?:var|let|const|function|class)\b\s+ )
|
817
|
+
# 第3组:变量名或函数名
|
818
|
+
(\w+).*?
|
819
|
+
# 第4组:不以{结尾的行,或者已{结尾的行且后续有配对的}
|
820
|
+
( (?:[^\{]\n) | (?:\{[\s\S]+?(?<=\n\}\n)) )
|
821
|
+
"""
|
822
|
+
matches = re.finditer(pattern, js_code, flags=re.VERBOSE)
|
823
|
+
|
824
|
+
definitions = {}
|
825
|
+
for match in matches:
|
826
|
+
identifier = match.group(3).strip() # 根据正则表达式的修改,更新捕获组的索引
|
827
|
+
full_definition = match.group(0).strip()
|
828
|
+
definitions[identifier] = full_definition
|
829
|
+
return definitions
|
830
|
+
|
831
|
+
|
832
|
+
def find_identifiers_in_code(code):
|
833
|
+
""" 正则实现的找标识符的版本
|
834
|
+
|
835
|
+
用基于esprima的语法树实现的方式,遇到不是那么标准的代码的时候,太多问题和局限了
|
836
|
+
还会多此一举过滤掉注释部分等
|
837
|
+
"""
|
838
|
+
return set(re.findall(r'\b(\w+)\b', code))
|
839
|
+
|
840
|
+
|
841
|
+
def find_direct_dependencies(definitions):
|
842
|
+
"""
|
843
|
+
查找每个定义中的直接依赖关系。
|
844
|
+
使用 esprima 提取代码中的标识符,并与定义列表求交集。
|
845
|
+
|
846
|
+
:param definitions: 要输入一组数据是因为只检查这一组内的命名空间的东西
|
847
|
+
"""
|
848
|
+
keys = set(definitions.keys())
|
849
|
+
dependencies = {key: [] for key in definitions}
|
850
|
+
|
851
|
+
for key, code in definitions.items():
|
852
|
+
identifiers = find_identifiers_in_code(code)
|
853
|
+
direct_deps = identifiers.intersection(keys)
|
854
|
+
dependencies[key] = list(direct_deps - {key}) # 排除自身
|
855
|
+
|
856
|
+
return dependencies
|
857
|
+
|
858
|
+
|
859
|
+
def assemble_dependencies_from_jstools(cur_code, jstools=None, place_tail=False, old_jsa=False):
|
860
|
+
"""
|
861
|
+
根据输入的 cur_code ,从预设的jstools工具代码库中自动提取所有相关依赖定义
|
862
|
+
|
863
|
+
:param str cur_node: 当前代码
|
864
|
+
:param str jstools: 依赖的工具代码
|
865
|
+
:param bool place_tail: 把工具代码放在末尾
|
866
|
+
放在末尾的目的,是类似jsa那样的场景能在开头直接看到关键的业务代码逻辑
|
867
|
+
|
868
|
+
一般大部分工具函数都是可以放在末尾的
|
869
|
+
但是要注意也有个别特殊的实现,是以定义变量的模式来使用的,则不能放倒末尾
|
870
|
+
|
871
|
+
"""
|
872
|
+
# 1 获得工具代码
|
873
|
+
# wps场景支持全局return处理,但这个在编译器里会报错,可以先暴力删掉,不影响我这里的相关处理逻辑
|
874
|
+
identifiers_in_input = find_identifiers_in_code(cur_code)
|
875
|
+
|
876
|
+
if jstools is None:
|
877
|
+
definitions = get_airscript_head2(True)
|
878
|
+
else:
|
879
|
+
definitions = extract_definitions_with_comments(jstools)
|
880
|
+
if old_jsa: # 如果使用的是旧版的jsa1.0,需要做个转换处理
|
881
|
+
# definitions字典里会有类似 as1_func 这样的key,还会有对应的 func 这样的key
|
882
|
+
# 将原本func的删掉,然后把as1_func替换成func的定义
|
883
|
+
# 注意字典替换后,value里的代码函数名等也要改掉
|
884
|
+
for key in list(definitions.keys()):
|
885
|
+
if key.startswith('as1_'):
|
886
|
+
definitions[key[4:]] = re.sub(r'(function\s+)as1_', r'\1', definitions[key])
|
887
|
+
|
888
|
+
# 2 找到所有使用到的符号
|
889
|
+
# 初始化结果列表,并按照 definitions 的顺序存储
|
890
|
+
visited = set()
|
891
|
+
dependencies = find_direct_dependencies(definitions)
|
892
|
+
|
893
|
+
def resolve_dependencies(identifier):
|
894
|
+
"""递归解决依赖,确保按照 definitions 的顺序添加"""
|
895
|
+
if identifier in visited:
|
896
|
+
return
|
897
|
+
visited.add(identifier)
|
898
|
+
for dep in dependencies[identifier]:
|
899
|
+
resolve_dependencies(dep)
|
900
|
+
|
901
|
+
# 从输入代码的标识符开始,递归查找依赖
|
902
|
+
for identifier in set(definitions.keys()).intersection(identifiers_in_input):
|
903
|
+
resolve_dependencies(identifier)
|
904
|
+
|
905
|
+
# 3 拼接代码
|
906
|
+
required_code = [definitions[identifier] for identifier in definitions if identifier in visited]
|
907
|
+
if place_tail:
|
908
|
+
# required_code.insert(0, '\n\n// 以下是工具代码')
|
909
|
+
required_code.insert(0, '\n\nfunction __x_工具代码() {\n}')
|
910
|
+
required_code.insert(0, cur_code)
|
911
|
+
else:
|
912
|
+
required_code.append(cur_code)
|
913
|
+
|
914
|
+
return "\n\n".join(required_code)
|
915
|
+
|
916
|
+
|
917
|
+
if __name__ == '__main__':
|
918
|
+
# 1 检查正则匹配从代码提取的结构化字典
|
919
|
+
# d = get_airscript_head2(True)
|
920
|
+
|
921
|
+
# 2 检查使用runIsolatedPyScript函数时提取依赖项的具体效果
|
922
|
+
print(assemble_dependencies_from_jstools('runIsolatedPyScript'))
|
pyxllib/text/nestenv.py
CHANGED
pyxllib/text/newbie.py
CHANGED
@@ -286,3 +286,15 @@ def fold_dict(d, m=5):
|
|
286
286
|
vals = [f"'{k}': {v}" for k, v in d.items()]
|
287
287
|
line = [', '.join(vals[i:i + 5]) for i in range(0, len(vals), m)]
|
288
288
|
return '{' + ',\n'.join(line) + '}'
|
289
|
+
|
290
|
+
|
291
|
+
def remove_prefix(original_string, prefix):
|
292
|
+
if original_string.startswith(prefix):
|
293
|
+
return original_string[len(prefix):]
|
294
|
+
return original_string
|
295
|
+
|
296
|
+
|
297
|
+
def remove_suffix(original_string, suffix):
|
298
|
+
if original_string.endswith(suffix):
|
299
|
+
return original_string[:-len(suffix)]
|
300
|
+
return original_string
|
pyxllib/text/pupil/common.py
CHANGED
@@ -1093,3 +1093,29 @@ def trial_jsoneditconveter():
|
|
1093
1093
|
trial_data(json_obj2)
|
1094
1094
|
trial_data(json_obj3)
|
1095
1095
|
trial_data(json_obj4)
|
1096
|
+
|
1097
|
+
|
1098
|
+
class UrlQueryBuilder:
|
1099
|
+
def __init__(self):
|
1100
|
+
self.params = {}
|
1101
|
+
|
1102
|
+
def add_param(self, key, value):
|
1103
|
+
if value is not None:
|
1104
|
+
self.params[key] = value
|
1105
|
+
return self
|
1106
|
+
|
1107
|
+
def remove_param(self, key):
|
1108
|
+
if key in self.params:
|
1109
|
+
del self.params[key]
|
1110
|
+
return self
|
1111
|
+
|
1112
|
+
def update_param(self, key, value):
|
1113
|
+
self.add_param(key, value)
|
1114
|
+
return self
|
1115
|
+
|
1116
|
+
def build_query(self):
|
1117
|
+
query_string = '&'.join([f'{key}={value}' for key, value in self.params.items()])
|
1118
|
+
return ('?' + query_string) if query_string else ''
|
1119
|
+
|
1120
|
+
def build_url(self, url):
|
1121
|
+
return f'{url}{self.build_query()}'
|
pyxllib/text/specialist/ptag.py
CHANGED
@@ -143,7 +143,7 @@ def brieftexstr(s):
|
|
143
143
|
# BRACE3 = '{(' + grp_bracket(3)[1:-1] + ')}'
|
144
144
|
# BRACE4 = '{(' + grp_bracket(4)[1:-1] + ')}'
|
145
145
|
# BRACE5 = '{(' + grp_bracket(5)[1:-1] + ')}'
|
146
|
-
"""使用示例
|
146
|
+
r""" 使用示例
|
147
147
|
>> m = re.search(r'\\multicolumn' + BRACE3*3, r'\multicolumn{2}{|c|}{$2^{12}$个数}')
|
148
148
|
>> m.groups()
|
149
149
|
('2', '|c|', '$2^{12}$个数')
|
@@ -160,7 +160,7 @@ def grp_topic(*, type_value=None):
|
|
160
160
|
|
161
161
|
|
162
162
|
def grp_figure(cnt_groups=0, parpic=False):
|
163
|
-
"""生成跟图片匹配相关的表达式
|
163
|
+
r""" 生成跟图片匹配相关的表达式
|
164
164
|
|
165
165
|
D:\2017LaTeX\D招培试卷\高中地理,用过 \captionfig{3-3.eps}{图~3}
|
166
166
|
奕本从2018秋季教材开始使用多种图片格式
|