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.
Files changed (306) hide show
  1. pyxllib/algo/geo.py +12 -0
  2. pyxllib/algo/intervals.py +1 -1
  3. pyxllib/algo/matcher.py +78 -0
  4. pyxllib/algo/pupil.py +187 -19
  5. pyxllib/algo/specialist.py +2 -1
  6. pyxllib/algo/stat.py +38 -2
  7. {pyxlpr → pyxllib/autogui}/__init__.py +1 -1
  8. pyxllib/autogui/activewin.py +246 -0
  9. pyxllib/autogui/all.py +9 -0
  10. pyxllib/{ext/autogui → autogui}/autogui.py +40 -11
  11. pyxllib/autogui/uiautolib.py +362 -0
  12. pyxllib/autogui/wechat.py +827 -0
  13. pyxllib/autogui/wechat_msg.py +421 -0
  14. pyxllib/autogui/wxautolib.py +84 -0
  15. pyxllib/cv/slidercaptcha.py +137 -0
  16. pyxllib/data/echarts.py +123 -12
  17. pyxllib/data/jsonlib.py +89 -0
  18. pyxllib/data/pglib.py +514 -30
  19. pyxllib/data/sqlite.py +231 -4
  20. pyxllib/ext/JLineViewer.py +14 -1
  21. pyxllib/ext/drissionlib.py +277 -0
  22. pyxllib/ext/kq5034lib.py +0 -1594
  23. pyxllib/ext/robustprocfile.py +497 -0
  24. pyxllib/ext/unixlib.py +6 -5
  25. pyxllib/ext/utools.py +108 -95
  26. pyxllib/ext/webhook.py +32 -14
  27. pyxllib/ext/wjxlib.py +88 -0
  28. pyxllib/ext/wpsapi.py +124 -0
  29. pyxllib/ext/xlwork.py +9 -0
  30. pyxllib/ext/yuquelib.py +1003 -71
  31. pyxllib/file/docxlib.py +1 -1
  32. pyxllib/file/libreoffice.py +165 -0
  33. pyxllib/file/movielib.py +9 -0
  34. pyxllib/file/packlib/__init__.py +112 -75
  35. pyxllib/file/pdflib.py +1 -1
  36. pyxllib/file/pupil.py +1 -1
  37. pyxllib/file/specialist/dirlib.py +1 -1
  38. pyxllib/file/specialist/download.py +10 -3
  39. pyxllib/file/specialist/filelib.py +266 -55
  40. pyxllib/file/xlsxlib.py +205 -50
  41. pyxllib/file/xlsyncfile.py +341 -0
  42. pyxllib/prog/cachetools.py +64 -0
  43. pyxllib/prog/filelock.py +42 -0
  44. pyxllib/prog/multiprogs.py +940 -0
  45. pyxllib/prog/newbie.py +9 -2
  46. pyxllib/prog/pupil.py +129 -60
  47. pyxllib/prog/specialist/__init__.py +176 -2
  48. pyxllib/prog/specialist/bc.py +5 -2
  49. pyxllib/prog/specialist/browser.py +11 -2
  50. pyxllib/prog/specialist/datetime.py +68 -0
  51. pyxllib/prog/specialist/tictoc.py +12 -13
  52. pyxllib/prog/specialist/xllog.py +5 -5
  53. pyxllib/prog/xlosenv.py +7 -0
  54. pyxllib/text/airscript.js +744 -0
  55. pyxllib/text/charclasslib.py +17 -5
  56. pyxllib/text/jiebalib.py +6 -3
  57. pyxllib/text/jinjalib.py +32 -0
  58. pyxllib/text/jsa_ai_prompt.md +271 -0
  59. pyxllib/text/jscode.py +159 -4
  60. pyxllib/text/nestenv.py +1 -1
  61. pyxllib/text/newbie.py +12 -0
  62. pyxllib/text/pupil/common.py +26 -0
  63. pyxllib/text/specialist/ptag.py +2 -2
  64. pyxllib/text/templates/echart_base.html +11 -0
  65. pyxllib/text/templates/highlight_code.html +17 -0
  66. pyxllib/text/templates/latex_editor.html +103 -0
  67. pyxllib/text/xmllib.py +76 -14
  68. pyxllib/xl.py +2 -1
  69. pyxllib-0.3.197.dist-info/METADATA +48 -0
  70. pyxllib-0.3.197.dist-info/RECORD +126 -0
  71. {pyxllib-0.3.96.dist-info → pyxllib-0.3.197.dist-info}/WHEEL +1 -2
  72. pyxllib/ext/autogui/__init__.py +0 -8
  73. pyxllib-0.3.96.dist-info/METADATA +0 -51
  74. pyxllib-0.3.96.dist-info/RECORD +0 -333
  75. pyxllib-0.3.96.dist-info/top_level.txt +0 -2
  76. pyxlpr/ai/__init__.py +0 -5
  77. pyxlpr/ai/clientlib.py +0 -1281
  78. pyxlpr/ai/specialist.py +0 -286
  79. pyxlpr/ai/torch_app.py +0 -172
  80. pyxlpr/ai/xlpaddle.py +0 -655
  81. pyxlpr/ai/xltorch.py +0 -705
  82. pyxlpr/data/__init__.py +0 -11
  83. pyxlpr/data/coco.py +0 -1325
  84. pyxlpr/data/datacls.py +0 -365
  85. pyxlpr/data/datasets.py +0 -200
  86. pyxlpr/data/gptlib.py +0 -1291
  87. pyxlpr/data/icdar/__init__.py +0 -96
  88. pyxlpr/data/icdar/deteval.py +0 -377
  89. pyxlpr/data/icdar/icdar2013.py +0 -341
  90. pyxlpr/data/icdar/iou.py +0 -340
  91. pyxlpr/data/icdar/rrc_evaluation_funcs_1_1.py +0 -463
  92. pyxlpr/data/imtextline.py +0 -473
  93. pyxlpr/data/labelme.py +0 -866
  94. pyxlpr/data/removeline.py +0 -179
  95. pyxlpr/data/specialist.py +0 -57
  96. pyxlpr/eval/__init__.py +0 -85
  97. pyxlpr/paddleocr.py +0 -776
  98. pyxlpr/ppocr/__init__.py +0 -15
  99. pyxlpr/ppocr/configs/rec/multi_language/generate_multi_language_configs.py +0 -226
  100. pyxlpr/ppocr/data/__init__.py +0 -135
  101. pyxlpr/ppocr/data/imaug/ColorJitter.py +0 -26
  102. pyxlpr/ppocr/data/imaug/__init__.py +0 -67
  103. pyxlpr/ppocr/data/imaug/copy_paste.py +0 -170
  104. pyxlpr/ppocr/data/imaug/east_process.py +0 -437
  105. pyxlpr/ppocr/data/imaug/gen_table_mask.py +0 -244
  106. pyxlpr/ppocr/data/imaug/iaa_augment.py +0 -114
  107. pyxlpr/ppocr/data/imaug/label_ops.py +0 -789
  108. pyxlpr/ppocr/data/imaug/make_border_map.py +0 -184
  109. pyxlpr/ppocr/data/imaug/make_pse_gt.py +0 -106
  110. pyxlpr/ppocr/data/imaug/make_shrink_map.py +0 -126
  111. pyxlpr/ppocr/data/imaug/operators.py +0 -433
  112. pyxlpr/ppocr/data/imaug/pg_process.py +0 -906
  113. pyxlpr/ppocr/data/imaug/randaugment.py +0 -143
  114. pyxlpr/ppocr/data/imaug/random_crop_data.py +0 -239
  115. pyxlpr/ppocr/data/imaug/rec_img_aug.py +0 -533
  116. pyxlpr/ppocr/data/imaug/sast_process.py +0 -777
  117. pyxlpr/ppocr/data/imaug/text_image_aug/__init__.py +0 -17
  118. pyxlpr/ppocr/data/imaug/text_image_aug/augment.py +0 -120
  119. pyxlpr/ppocr/data/imaug/text_image_aug/warp_mls.py +0 -168
  120. pyxlpr/ppocr/data/lmdb_dataset.py +0 -115
  121. pyxlpr/ppocr/data/pgnet_dataset.py +0 -104
  122. pyxlpr/ppocr/data/pubtab_dataset.py +0 -107
  123. pyxlpr/ppocr/data/simple_dataset.py +0 -372
  124. pyxlpr/ppocr/losses/__init__.py +0 -61
  125. pyxlpr/ppocr/losses/ace_loss.py +0 -52
  126. pyxlpr/ppocr/losses/basic_loss.py +0 -135
  127. pyxlpr/ppocr/losses/center_loss.py +0 -88
  128. pyxlpr/ppocr/losses/cls_loss.py +0 -30
  129. pyxlpr/ppocr/losses/combined_loss.py +0 -67
  130. pyxlpr/ppocr/losses/det_basic_loss.py +0 -208
  131. pyxlpr/ppocr/losses/det_db_loss.py +0 -80
  132. pyxlpr/ppocr/losses/det_east_loss.py +0 -63
  133. pyxlpr/ppocr/losses/det_pse_loss.py +0 -149
  134. pyxlpr/ppocr/losses/det_sast_loss.py +0 -121
  135. pyxlpr/ppocr/losses/distillation_loss.py +0 -272
  136. pyxlpr/ppocr/losses/e2e_pg_loss.py +0 -140
  137. pyxlpr/ppocr/losses/kie_sdmgr_loss.py +0 -113
  138. pyxlpr/ppocr/losses/rec_aster_loss.py +0 -99
  139. pyxlpr/ppocr/losses/rec_att_loss.py +0 -39
  140. pyxlpr/ppocr/losses/rec_ctc_loss.py +0 -44
  141. pyxlpr/ppocr/losses/rec_enhanced_ctc_loss.py +0 -70
  142. pyxlpr/ppocr/losses/rec_nrtr_loss.py +0 -30
  143. pyxlpr/ppocr/losses/rec_sar_loss.py +0 -28
  144. pyxlpr/ppocr/losses/rec_srn_loss.py +0 -47
  145. pyxlpr/ppocr/losses/table_att_loss.py +0 -109
  146. pyxlpr/ppocr/metrics/__init__.py +0 -44
  147. pyxlpr/ppocr/metrics/cls_metric.py +0 -45
  148. pyxlpr/ppocr/metrics/det_metric.py +0 -82
  149. pyxlpr/ppocr/metrics/distillation_metric.py +0 -73
  150. pyxlpr/ppocr/metrics/e2e_metric.py +0 -86
  151. pyxlpr/ppocr/metrics/eval_det_iou.py +0 -274
  152. pyxlpr/ppocr/metrics/kie_metric.py +0 -70
  153. pyxlpr/ppocr/metrics/rec_metric.py +0 -75
  154. pyxlpr/ppocr/metrics/table_metric.py +0 -50
  155. pyxlpr/ppocr/modeling/architectures/__init__.py +0 -32
  156. pyxlpr/ppocr/modeling/architectures/base_model.py +0 -88
  157. pyxlpr/ppocr/modeling/architectures/distillation_model.py +0 -60
  158. pyxlpr/ppocr/modeling/backbones/__init__.py +0 -54
  159. pyxlpr/ppocr/modeling/backbones/det_mobilenet_v3.py +0 -268
  160. pyxlpr/ppocr/modeling/backbones/det_resnet_vd.py +0 -246
  161. pyxlpr/ppocr/modeling/backbones/det_resnet_vd_sast.py +0 -285
  162. pyxlpr/ppocr/modeling/backbones/e2e_resnet_vd_pg.py +0 -265
  163. pyxlpr/ppocr/modeling/backbones/kie_unet_sdmgr.py +0 -186
  164. pyxlpr/ppocr/modeling/backbones/rec_mobilenet_v3.py +0 -138
  165. pyxlpr/ppocr/modeling/backbones/rec_mv1_enhance.py +0 -258
  166. pyxlpr/ppocr/modeling/backbones/rec_nrtr_mtb.py +0 -48
  167. pyxlpr/ppocr/modeling/backbones/rec_resnet_31.py +0 -210
  168. pyxlpr/ppocr/modeling/backbones/rec_resnet_aster.py +0 -143
  169. pyxlpr/ppocr/modeling/backbones/rec_resnet_fpn.py +0 -307
  170. pyxlpr/ppocr/modeling/backbones/rec_resnet_vd.py +0 -286
  171. pyxlpr/ppocr/modeling/heads/__init__.py +0 -54
  172. pyxlpr/ppocr/modeling/heads/cls_head.py +0 -52
  173. pyxlpr/ppocr/modeling/heads/det_db_head.py +0 -118
  174. pyxlpr/ppocr/modeling/heads/det_east_head.py +0 -121
  175. pyxlpr/ppocr/modeling/heads/det_pse_head.py +0 -37
  176. pyxlpr/ppocr/modeling/heads/det_sast_head.py +0 -128
  177. pyxlpr/ppocr/modeling/heads/e2e_pg_head.py +0 -253
  178. pyxlpr/ppocr/modeling/heads/kie_sdmgr_head.py +0 -206
  179. pyxlpr/ppocr/modeling/heads/multiheadAttention.py +0 -163
  180. pyxlpr/ppocr/modeling/heads/rec_aster_head.py +0 -393
  181. pyxlpr/ppocr/modeling/heads/rec_att_head.py +0 -202
  182. pyxlpr/ppocr/modeling/heads/rec_ctc_head.py +0 -88
  183. pyxlpr/ppocr/modeling/heads/rec_nrtr_head.py +0 -826
  184. pyxlpr/ppocr/modeling/heads/rec_sar_head.py +0 -402
  185. pyxlpr/ppocr/modeling/heads/rec_srn_head.py +0 -280
  186. pyxlpr/ppocr/modeling/heads/self_attention.py +0 -406
  187. pyxlpr/ppocr/modeling/heads/table_att_head.py +0 -246
  188. pyxlpr/ppocr/modeling/necks/__init__.py +0 -32
  189. pyxlpr/ppocr/modeling/necks/db_fpn.py +0 -111
  190. pyxlpr/ppocr/modeling/necks/east_fpn.py +0 -188
  191. pyxlpr/ppocr/modeling/necks/fpn.py +0 -138
  192. pyxlpr/ppocr/modeling/necks/pg_fpn.py +0 -314
  193. pyxlpr/ppocr/modeling/necks/rnn.py +0 -92
  194. pyxlpr/ppocr/modeling/necks/sast_fpn.py +0 -284
  195. pyxlpr/ppocr/modeling/necks/table_fpn.py +0 -110
  196. pyxlpr/ppocr/modeling/transforms/__init__.py +0 -28
  197. pyxlpr/ppocr/modeling/transforms/stn.py +0 -135
  198. pyxlpr/ppocr/modeling/transforms/tps.py +0 -308
  199. pyxlpr/ppocr/modeling/transforms/tps_spatial_transformer.py +0 -156
  200. pyxlpr/ppocr/optimizer/__init__.py +0 -61
  201. pyxlpr/ppocr/optimizer/learning_rate.py +0 -228
  202. pyxlpr/ppocr/optimizer/lr_scheduler.py +0 -49
  203. pyxlpr/ppocr/optimizer/optimizer.py +0 -160
  204. pyxlpr/ppocr/optimizer/regularizer.py +0 -52
  205. pyxlpr/ppocr/postprocess/__init__.py +0 -55
  206. pyxlpr/ppocr/postprocess/cls_postprocess.py +0 -33
  207. pyxlpr/ppocr/postprocess/db_postprocess.py +0 -234
  208. pyxlpr/ppocr/postprocess/east_postprocess.py +0 -143
  209. pyxlpr/ppocr/postprocess/locality_aware_nms.py +0 -200
  210. pyxlpr/ppocr/postprocess/pg_postprocess.py +0 -52
  211. pyxlpr/ppocr/postprocess/pse_postprocess/__init__.py +0 -15
  212. pyxlpr/ppocr/postprocess/pse_postprocess/pse/__init__.py +0 -29
  213. pyxlpr/ppocr/postprocess/pse_postprocess/pse/setup.py +0 -14
  214. pyxlpr/ppocr/postprocess/pse_postprocess/pse_postprocess.py +0 -118
  215. pyxlpr/ppocr/postprocess/rec_postprocess.py +0 -654
  216. pyxlpr/ppocr/postprocess/sast_postprocess.py +0 -355
  217. pyxlpr/ppocr/tools/__init__.py +0 -14
  218. pyxlpr/ppocr/tools/eval.py +0 -83
  219. pyxlpr/ppocr/tools/export_center.py +0 -77
  220. pyxlpr/ppocr/tools/export_model.py +0 -129
  221. pyxlpr/ppocr/tools/infer/predict_cls.py +0 -151
  222. pyxlpr/ppocr/tools/infer/predict_det.py +0 -300
  223. pyxlpr/ppocr/tools/infer/predict_e2e.py +0 -169
  224. pyxlpr/ppocr/tools/infer/predict_rec.py +0 -414
  225. pyxlpr/ppocr/tools/infer/predict_system.py +0 -204
  226. pyxlpr/ppocr/tools/infer/utility.py +0 -629
  227. pyxlpr/ppocr/tools/infer_cls.py +0 -83
  228. pyxlpr/ppocr/tools/infer_det.py +0 -134
  229. pyxlpr/ppocr/tools/infer_e2e.py +0 -122
  230. pyxlpr/ppocr/tools/infer_kie.py +0 -153
  231. pyxlpr/ppocr/tools/infer_rec.py +0 -146
  232. pyxlpr/ppocr/tools/infer_table.py +0 -107
  233. pyxlpr/ppocr/tools/program.py +0 -596
  234. pyxlpr/ppocr/tools/test_hubserving.py +0 -117
  235. pyxlpr/ppocr/tools/train.py +0 -163
  236. pyxlpr/ppocr/tools/xlprog.py +0 -748
  237. pyxlpr/ppocr/utils/EN_symbol_dict.txt +0 -94
  238. pyxlpr/ppocr/utils/__init__.py +0 -24
  239. pyxlpr/ppocr/utils/dict/ar_dict.txt +0 -117
  240. pyxlpr/ppocr/utils/dict/arabic_dict.txt +0 -162
  241. pyxlpr/ppocr/utils/dict/be_dict.txt +0 -145
  242. pyxlpr/ppocr/utils/dict/bg_dict.txt +0 -140
  243. pyxlpr/ppocr/utils/dict/chinese_cht_dict.txt +0 -8421
  244. pyxlpr/ppocr/utils/dict/cyrillic_dict.txt +0 -163
  245. pyxlpr/ppocr/utils/dict/devanagari_dict.txt +0 -167
  246. pyxlpr/ppocr/utils/dict/en_dict.txt +0 -63
  247. pyxlpr/ppocr/utils/dict/fa_dict.txt +0 -136
  248. pyxlpr/ppocr/utils/dict/french_dict.txt +0 -136
  249. pyxlpr/ppocr/utils/dict/german_dict.txt +0 -143
  250. pyxlpr/ppocr/utils/dict/hi_dict.txt +0 -162
  251. pyxlpr/ppocr/utils/dict/it_dict.txt +0 -118
  252. pyxlpr/ppocr/utils/dict/japan_dict.txt +0 -4399
  253. pyxlpr/ppocr/utils/dict/ka_dict.txt +0 -153
  254. pyxlpr/ppocr/utils/dict/korean_dict.txt +0 -3688
  255. pyxlpr/ppocr/utils/dict/latin_dict.txt +0 -185
  256. pyxlpr/ppocr/utils/dict/mr_dict.txt +0 -153
  257. pyxlpr/ppocr/utils/dict/ne_dict.txt +0 -153
  258. pyxlpr/ppocr/utils/dict/oc_dict.txt +0 -96
  259. pyxlpr/ppocr/utils/dict/pu_dict.txt +0 -130
  260. pyxlpr/ppocr/utils/dict/rs_dict.txt +0 -91
  261. pyxlpr/ppocr/utils/dict/rsc_dict.txt +0 -134
  262. pyxlpr/ppocr/utils/dict/ru_dict.txt +0 -125
  263. pyxlpr/ppocr/utils/dict/ta_dict.txt +0 -128
  264. pyxlpr/ppocr/utils/dict/table_dict.txt +0 -277
  265. pyxlpr/ppocr/utils/dict/table_structure_dict.txt +0 -2759
  266. pyxlpr/ppocr/utils/dict/te_dict.txt +0 -151
  267. pyxlpr/ppocr/utils/dict/ug_dict.txt +0 -114
  268. pyxlpr/ppocr/utils/dict/uk_dict.txt +0 -142
  269. pyxlpr/ppocr/utils/dict/ur_dict.txt +0 -137
  270. pyxlpr/ppocr/utils/dict/xi_dict.txt +0 -110
  271. pyxlpr/ppocr/utils/dict90.txt +0 -90
  272. pyxlpr/ppocr/utils/e2e_metric/Deteval.py +0 -574
  273. pyxlpr/ppocr/utils/e2e_metric/polygon_fast.py +0 -83
  274. pyxlpr/ppocr/utils/e2e_utils/extract_batchsize.py +0 -87
  275. pyxlpr/ppocr/utils/e2e_utils/extract_textpoint_fast.py +0 -457
  276. pyxlpr/ppocr/utils/e2e_utils/extract_textpoint_slow.py +0 -592
  277. pyxlpr/ppocr/utils/e2e_utils/pgnet_pp_utils.py +0 -162
  278. pyxlpr/ppocr/utils/e2e_utils/visual.py +0 -162
  279. pyxlpr/ppocr/utils/en_dict.txt +0 -95
  280. pyxlpr/ppocr/utils/gen_label.py +0 -81
  281. pyxlpr/ppocr/utils/ic15_dict.txt +0 -36
  282. pyxlpr/ppocr/utils/iou.py +0 -54
  283. pyxlpr/ppocr/utils/logging.py +0 -69
  284. pyxlpr/ppocr/utils/network.py +0 -84
  285. pyxlpr/ppocr/utils/ppocr_keys_v1.txt +0 -6623
  286. pyxlpr/ppocr/utils/profiler.py +0 -110
  287. pyxlpr/ppocr/utils/save_load.py +0 -150
  288. pyxlpr/ppocr/utils/stats.py +0 -72
  289. pyxlpr/ppocr/utils/utility.py +0 -80
  290. pyxlpr/ppstructure/__init__.py +0 -13
  291. pyxlpr/ppstructure/predict_system.py +0 -187
  292. pyxlpr/ppstructure/table/__init__.py +0 -13
  293. pyxlpr/ppstructure/table/eval_table.py +0 -72
  294. pyxlpr/ppstructure/table/matcher.py +0 -192
  295. pyxlpr/ppstructure/table/predict_structure.py +0 -136
  296. pyxlpr/ppstructure/table/predict_table.py +0 -221
  297. pyxlpr/ppstructure/table/table_metric/__init__.py +0 -16
  298. pyxlpr/ppstructure/table/table_metric/parallel.py +0 -51
  299. pyxlpr/ppstructure/table/table_metric/table_metric.py +0 -247
  300. pyxlpr/ppstructure/table/tablepyxl/__init__.py +0 -13
  301. pyxlpr/ppstructure/table/tablepyxl/style.py +0 -283
  302. pyxlpr/ppstructure/table/tablepyxl/tablepyxl.py +0 -118
  303. pyxlpr/ppstructure/utility.py +0 -71
  304. pyxlpr/xlai.py +0 -10
  305. /pyxllib/{ext/autogui → autogui}/virtualkey.py +0 -0
  306. {pyxllib-0.3.96.dist-info → pyxllib-0.3.197.dist-info/licenses}/LICENSE +0 -0
@@ -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
- # todo 这里的规则应该还可以再优化,以及不同的业务场景,这些规则应该也要再调整
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['其他字符'] / ct['字母'] > 0.1:
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, add_flag=False):
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, add_flag=add_flag)
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, '优化向量'):
@@ -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', code_text)
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, flags=re.DOTALL)
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
- if __name__ == '__main__':
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
@@ -865,7 +865,7 @@ class LatexNestEnv(NestEnv):
865
865
  return self.nest(core, invert)
866
866
 
867
867
  def latexenv1(self, inner=False, invert=False):
868
- """ 定位文本中所有最外层的 \begin、\end 环境
868
+ r""" 定位文本中所有最外层的 \begin、\end 环境
869
869
 
870
870
  这个函数需要依赖基础功能latexenv来实现
871
871
  """
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
@@ -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()}'
@@ -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秋季教材开始使用多种图片格式