pyxllib 0.3.96__py3-none-any.whl → 0.3.200__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 (358) hide show
  1. pyxllib/__init__.py +21 -21
  2. pyxllib/algo/__init__.py +8 -8
  3. pyxllib/algo/disjoint.py +54 -54
  4. pyxllib/algo/geo.py +541 -529
  5. pyxllib/algo/intervals.py +964 -964
  6. pyxllib/algo/matcher.py +389 -311
  7. pyxllib/algo/newbie.py +166 -166
  8. pyxllib/algo/pupil.py +629 -461
  9. pyxllib/algo/shapelylib.py +67 -67
  10. pyxllib/algo/specialist.py +241 -240
  11. pyxllib/algo/stat.py +494 -458
  12. pyxllib/algo/treelib.py +149 -149
  13. pyxllib/algo/unitlib.py +66 -66
  14. {pyxlpr → pyxllib/autogui}/__init__.py +5 -5
  15. pyxllib/autogui/activewin.py +246 -0
  16. pyxllib/autogui/all.py +9 -0
  17. pyxllib/{ext/autogui → autogui}/autogui.py +852 -823
  18. pyxllib/autogui/uiautolib.py +362 -0
  19. pyxllib/{ext/autogui → autogui}/virtualkey.py +102 -102
  20. pyxllib/autogui/wechat.py +827 -0
  21. pyxllib/autogui/wechat_msg.py +421 -0
  22. pyxllib/autogui/wxautolib.py +84 -0
  23. pyxllib/cv/__init__.py +5 -5
  24. pyxllib/cv/expert.py +267 -267
  25. pyxllib/cv/imfile.py +159 -159
  26. pyxllib/cv/imhash.py +39 -39
  27. pyxllib/cv/pupil.py +9 -9
  28. pyxllib/cv/rgbfmt.py +1525 -1525
  29. pyxllib/cv/slidercaptcha.py +137 -0
  30. pyxllib/cv/trackbartools.py +251 -251
  31. pyxllib/cv/xlcvlib.py +1040 -1040
  32. pyxllib/cv/xlpillib.py +423 -423
  33. pyxllib/data/echarts.py +240 -129
  34. pyxllib/data/jsonlib.py +89 -0
  35. pyxllib/data/oss.py +72 -72
  36. pyxllib/data/pglib.py +1127 -643
  37. pyxllib/data/sqlite.py +568 -341
  38. pyxllib/data/sqllib.py +297 -297
  39. pyxllib/ext/JLineViewer.py +505 -492
  40. pyxllib/ext/__init__.py +6 -6
  41. pyxllib/ext/demolib.py +246 -246
  42. pyxllib/ext/drissionlib.py +277 -0
  43. pyxllib/ext/kq5034lib.py +12 -1606
  44. pyxllib/ext/old.py +663 -663
  45. pyxllib/ext/qt.py +449 -449
  46. pyxllib/ext/robustprocfile.py +497 -0
  47. pyxllib/ext/seleniumlib.py +76 -76
  48. pyxllib/ext/tk.py +173 -173
  49. pyxllib/ext/unixlib.py +827 -826
  50. pyxllib/ext/utools.py +351 -338
  51. pyxllib/ext/webhook.py +124 -101
  52. pyxllib/ext/win32lib.py +40 -40
  53. pyxllib/ext/wjxlib.py +88 -0
  54. pyxllib/ext/wpsapi.py +124 -0
  55. pyxllib/ext/xlwork.py +9 -0
  56. pyxllib/ext/yuquelib.py +1105 -173
  57. pyxllib/file/__init__.py +17 -17
  58. pyxllib/file/docxlib.py +761 -761
  59. pyxllib/file/gitlib.py +309 -309
  60. pyxllib/file/libreoffice.py +165 -0
  61. pyxllib/file/movielib.py +148 -139
  62. pyxllib/file/newbie.py +10 -10
  63. pyxllib/file/onenotelib.py +1469 -1469
  64. pyxllib/file/packlib/__init__.py +330 -293
  65. pyxllib/file/packlib/zipfile.py +2441 -2441
  66. pyxllib/file/pdflib.py +426 -426
  67. pyxllib/file/pupil.py +185 -185
  68. pyxllib/file/specialist/__init__.py +685 -685
  69. pyxllib/file/specialist/dirlib.py +799 -799
  70. pyxllib/file/specialist/download.py +193 -186
  71. pyxllib/file/specialist/filelib.py +2829 -2618
  72. pyxllib/file/xlsxlib.py +3131 -2976
  73. pyxllib/file/xlsyncfile.py +341 -0
  74. pyxllib/prog/__init__.py +5 -5
  75. pyxllib/prog/cachetools.py +64 -0
  76. pyxllib/prog/deprecatedlib.py +233 -233
  77. pyxllib/prog/filelock.py +42 -0
  78. pyxllib/prog/ipyexec.py +253 -253
  79. pyxllib/prog/multiprogs.py +940 -0
  80. pyxllib/prog/newbie.py +451 -444
  81. pyxllib/prog/pupil.py +1197 -1128
  82. pyxllib/prog/sitepackages.py +33 -33
  83. pyxllib/prog/specialist/__init__.py +391 -217
  84. pyxllib/prog/specialist/bc.py +203 -200
  85. pyxllib/prog/specialist/browser.py +497 -488
  86. pyxllib/prog/specialist/common.py +347 -347
  87. pyxllib/prog/specialist/datetime.py +199 -131
  88. pyxllib/prog/specialist/tictoc.py +240 -241
  89. pyxllib/prog/specialist/xllog.py +180 -180
  90. pyxllib/prog/xlosenv.py +108 -101
  91. pyxllib/stdlib/__init__.py +17 -17
  92. pyxllib/stdlib/tablepyxl/__init__.py +10 -10
  93. pyxllib/stdlib/tablepyxl/style.py +303 -303
  94. pyxllib/stdlib/tablepyxl/tablepyxl.py +130 -130
  95. pyxllib/text/__init__.py +8 -8
  96. pyxllib/text/ahocorasick.py +39 -39
  97. pyxllib/text/airscript.js +744 -0
  98. pyxllib/text/charclasslib.py +121 -109
  99. pyxllib/text/jiebalib.py +267 -264
  100. pyxllib/text/jinjalib.py +32 -0
  101. pyxllib/text/jsa_ai_prompt.md +271 -0
  102. pyxllib/text/jscode.py +922 -767
  103. pyxllib/text/latex/__init__.py +158 -158
  104. pyxllib/text/levenshtein.py +303 -303
  105. pyxllib/text/nestenv.py +1215 -1215
  106. pyxllib/text/newbie.py +300 -288
  107. pyxllib/text/pupil/__init__.py +8 -8
  108. pyxllib/text/pupil/common.py +1121 -1095
  109. pyxllib/text/pupil/xlalign.py +326 -326
  110. pyxllib/text/pycode.py +47 -47
  111. pyxllib/text/specialist/__init__.py +8 -8
  112. pyxllib/text/specialist/common.py +112 -112
  113. pyxllib/text/specialist/ptag.py +186 -186
  114. pyxllib/text/spellchecker.py +172 -172
  115. pyxllib/text/templates/echart_base.html +11 -0
  116. pyxllib/text/templates/highlight_code.html +17 -0
  117. pyxllib/text/templates/latex_editor.html +103 -0
  118. pyxllib/text/vbacode.py +17 -17
  119. pyxllib/text/xmllib.py +747 -685
  120. pyxllib/xl.py +42 -38
  121. pyxllib/xlcv.py +17 -17
  122. pyxllib-0.3.200.dist-info/METADATA +48 -0
  123. pyxllib-0.3.200.dist-info/RECORD +126 -0
  124. {pyxllib-0.3.96.dist-info → pyxllib-0.3.200.dist-info}/WHEEL +1 -2
  125. {pyxllib-0.3.96.dist-info → pyxllib-0.3.200.dist-info/licenses}/LICENSE +190 -190
  126. pyxllib/ext/autogui/__init__.py +0 -8
  127. pyxllib-0.3.96.dist-info/METADATA +0 -51
  128. pyxllib-0.3.96.dist-info/RECORD +0 -333
  129. pyxllib-0.3.96.dist-info/top_level.txt +0 -2
  130. pyxlpr/ai/__init__.py +0 -5
  131. pyxlpr/ai/clientlib.py +0 -1281
  132. pyxlpr/ai/specialist.py +0 -286
  133. pyxlpr/ai/torch_app.py +0 -172
  134. pyxlpr/ai/xlpaddle.py +0 -655
  135. pyxlpr/ai/xltorch.py +0 -705
  136. pyxlpr/data/__init__.py +0 -11
  137. pyxlpr/data/coco.py +0 -1325
  138. pyxlpr/data/datacls.py +0 -365
  139. pyxlpr/data/datasets.py +0 -200
  140. pyxlpr/data/gptlib.py +0 -1291
  141. pyxlpr/data/icdar/__init__.py +0 -96
  142. pyxlpr/data/icdar/deteval.py +0 -377
  143. pyxlpr/data/icdar/icdar2013.py +0 -341
  144. pyxlpr/data/icdar/iou.py +0 -340
  145. pyxlpr/data/icdar/rrc_evaluation_funcs_1_1.py +0 -463
  146. pyxlpr/data/imtextline.py +0 -473
  147. pyxlpr/data/labelme.py +0 -866
  148. pyxlpr/data/removeline.py +0 -179
  149. pyxlpr/data/specialist.py +0 -57
  150. pyxlpr/eval/__init__.py +0 -85
  151. pyxlpr/paddleocr.py +0 -776
  152. pyxlpr/ppocr/__init__.py +0 -15
  153. pyxlpr/ppocr/configs/rec/multi_language/generate_multi_language_configs.py +0 -226
  154. pyxlpr/ppocr/data/__init__.py +0 -135
  155. pyxlpr/ppocr/data/imaug/ColorJitter.py +0 -26
  156. pyxlpr/ppocr/data/imaug/__init__.py +0 -67
  157. pyxlpr/ppocr/data/imaug/copy_paste.py +0 -170
  158. pyxlpr/ppocr/data/imaug/east_process.py +0 -437
  159. pyxlpr/ppocr/data/imaug/gen_table_mask.py +0 -244
  160. pyxlpr/ppocr/data/imaug/iaa_augment.py +0 -114
  161. pyxlpr/ppocr/data/imaug/label_ops.py +0 -789
  162. pyxlpr/ppocr/data/imaug/make_border_map.py +0 -184
  163. pyxlpr/ppocr/data/imaug/make_pse_gt.py +0 -106
  164. pyxlpr/ppocr/data/imaug/make_shrink_map.py +0 -126
  165. pyxlpr/ppocr/data/imaug/operators.py +0 -433
  166. pyxlpr/ppocr/data/imaug/pg_process.py +0 -906
  167. pyxlpr/ppocr/data/imaug/randaugment.py +0 -143
  168. pyxlpr/ppocr/data/imaug/random_crop_data.py +0 -239
  169. pyxlpr/ppocr/data/imaug/rec_img_aug.py +0 -533
  170. pyxlpr/ppocr/data/imaug/sast_process.py +0 -777
  171. pyxlpr/ppocr/data/imaug/text_image_aug/__init__.py +0 -17
  172. pyxlpr/ppocr/data/imaug/text_image_aug/augment.py +0 -120
  173. pyxlpr/ppocr/data/imaug/text_image_aug/warp_mls.py +0 -168
  174. pyxlpr/ppocr/data/lmdb_dataset.py +0 -115
  175. pyxlpr/ppocr/data/pgnet_dataset.py +0 -104
  176. pyxlpr/ppocr/data/pubtab_dataset.py +0 -107
  177. pyxlpr/ppocr/data/simple_dataset.py +0 -372
  178. pyxlpr/ppocr/losses/__init__.py +0 -61
  179. pyxlpr/ppocr/losses/ace_loss.py +0 -52
  180. pyxlpr/ppocr/losses/basic_loss.py +0 -135
  181. pyxlpr/ppocr/losses/center_loss.py +0 -88
  182. pyxlpr/ppocr/losses/cls_loss.py +0 -30
  183. pyxlpr/ppocr/losses/combined_loss.py +0 -67
  184. pyxlpr/ppocr/losses/det_basic_loss.py +0 -208
  185. pyxlpr/ppocr/losses/det_db_loss.py +0 -80
  186. pyxlpr/ppocr/losses/det_east_loss.py +0 -63
  187. pyxlpr/ppocr/losses/det_pse_loss.py +0 -149
  188. pyxlpr/ppocr/losses/det_sast_loss.py +0 -121
  189. pyxlpr/ppocr/losses/distillation_loss.py +0 -272
  190. pyxlpr/ppocr/losses/e2e_pg_loss.py +0 -140
  191. pyxlpr/ppocr/losses/kie_sdmgr_loss.py +0 -113
  192. pyxlpr/ppocr/losses/rec_aster_loss.py +0 -99
  193. pyxlpr/ppocr/losses/rec_att_loss.py +0 -39
  194. pyxlpr/ppocr/losses/rec_ctc_loss.py +0 -44
  195. pyxlpr/ppocr/losses/rec_enhanced_ctc_loss.py +0 -70
  196. pyxlpr/ppocr/losses/rec_nrtr_loss.py +0 -30
  197. pyxlpr/ppocr/losses/rec_sar_loss.py +0 -28
  198. pyxlpr/ppocr/losses/rec_srn_loss.py +0 -47
  199. pyxlpr/ppocr/losses/table_att_loss.py +0 -109
  200. pyxlpr/ppocr/metrics/__init__.py +0 -44
  201. pyxlpr/ppocr/metrics/cls_metric.py +0 -45
  202. pyxlpr/ppocr/metrics/det_metric.py +0 -82
  203. pyxlpr/ppocr/metrics/distillation_metric.py +0 -73
  204. pyxlpr/ppocr/metrics/e2e_metric.py +0 -86
  205. pyxlpr/ppocr/metrics/eval_det_iou.py +0 -274
  206. pyxlpr/ppocr/metrics/kie_metric.py +0 -70
  207. pyxlpr/ppocr/metrics/rec_metric.py +0 -75
  208. pyxlpr/ppocr/metrics/table_metric.py +0 -50
  209. pyxlpr/ppocr/modeling/architectures/__init__.py +0 -32
  210. pyxlpr/ppocr/modeling/architectures/base_model.py +0 -88
  211. pyxlpr/ppocr/modeling/architectures/distillation_model.py +0 -60
  212. pyxlpr/ppocr/modeling/backbones/__init__.py +0 -54
  213. pyxlpr/ppocr/modeling/backbones/det_mobilenet_v3.py +0 -268
  214. pyxlpr/ppocr/modeling/backbones/det_resnet_vd.py +0 -246
  215. pyxlpr/ppocr/modeling/backbones/det_resnet_vd_sast.py +0 -285
  216. pyxlpr/ppocr/modeling/backbones/e2e_resnet_vd_pg.py +0 -265
  217. pyxlpr/ppocr/modeling/backbones/kie_unet_sdmgr.py +0 -186
  218. pyxlpr/ppocr/modeling/backbones/rec_mobilenet_v3.py +0 -138
  219. pyxlpr/ppocr/modeling/backbones/rec_mv1_enhance.py +0 -258
  220. pyxlpr/ppocr/modeling/backbones/rec_nrtr_mtb.py +0 -48
  221. pyxlpr/ppocr/modeling/backbones/rec_resnet_31.py +0 -210
  222. pyxlpr/ppocr/modeling/backbones/rec_resnet_aster.py +0 -143
  223. pyxlpr/ppocr/modeling/backbones/rec_resnet_fpn.py +0 -307
  224. pyxlpr/ppocr/modeling/backbones/rec_resnet_vd.py +0 -286
  225. pyxlpr/ppocr/modeling/heads/__init__.py +0 -54
  226. pyxlpr/ppocr/modeling/heads/cls_head.py +0 -52
  227. pyxlpr/ppocr/modeling/heads/det_db_head.py +0 -118
  228. pyxlpr/ppocr/modeling/heads/det_east_head.py +0 -121
  229. pyxlpr/ppocr/modeling/heads/det_pse_head.py +0 -37
  230. pyxlpr/ppocr/modeling/heads/det_sast_head.py +0 -128
  231. pyxlpr/ppocr/modeling/heads/e2e_pg_head.py +0 -253
  232. pyxlpr/ppocr/modeling/heads/kie_sdmgr_head.py +0 -206
  233. pyxlpr/ppocr/modeling/heads/multiheadAttention.py +0 -163
  234. pyxlpr/ppocr/modeling/heads/rec_aster_head.py +0 -393
  235. pyxlpr/ppocr/modeling/heads/rec_att_head.py +0 -202
  236. pyxlpr/ppocr/modeling/heads/rec_ctc_head.py +0 -88
  237. pyxlpr/ppocr/modeling/heads/rec_nrtr_head.py +0 -826
  238. pyxlpr/ppocr/modeling/heads/rec_sar_head.py +0 -402
  239. pyxlpr/ppocr/modeling/heads/rec_srn_head.py +0 -280
  240. pyxlpr/ppocr/modeling/heads/self_attention.py +0 -406
  241. pyxlpr/ppocr/modeling/heads/table_att_head.py +0 -246
  242. pyxlpr/ppocr/modeling/necks/__init__.py +0 -32
  243. pyxlpr/ppocr/modeling/necks/db_fpn.py +0 -111
  244. pyxlpr/ppocr/modeling/necks/east_fpn.py +0 -188
  245. pyxlpr/ppocr/modeling/necks/fpn.py +0 -138
  246. pyxlpr/ppocr/modeling/necks/pg_fpn.py +0 -314
  247. pyxlpr/ppocr/modeling/necks/rnn.py +0 -92
  248. pyxlpr/ppocr/modeling/necks/sast_fpn.py +0 -284
  249. pyxlpr/ppocr/modeling/necks/table_fpn.py +0 -110
  250. pyxlpr/ppocr/modeling/transforms/__init__.py +0 -28
  251. pyxlpr/ppocr/modeling/transforms/stn.py +0 -135
  252. pyxlpr/ppocr/modeling/transforms/tps.py +0 -308
  253. pyxlpr/ppocr/modeling/transforms/tps_spatial_transformer.py +0 -156
  254. pyxlpr/ppocr/optimizer/__init__.py +0 -61
  255. pyxlpr/ppocr/optimizer/learning_rate.py +0 -228
  256. pyxlpr/ppocr/optimizer/lr_scheduler.py +0 -49
  257. pyxlpr/ppocr/optimizer/optimizer.py +0 -160
  258. pyxlpr/ppocr/optimizer/regularizer.py +0 -52
  259. pyxlpr/ppocr/postprocess/__init__.py +0 -55
  260. pyxlpr/ppocr/postprocess/cls_postprocess.py +0 -33
  261. pyxlpr/ppocr/postprocess/db_postprocess.py +0 -234
  262. pyxlpr/ppocr/postprocess/east_postprocess.py +0 -143
  263. pyxlpr/ppocr/postprocess/locality_aware_nms.py +0 -200
  264. pyxlpr/ppocr/postprocess/pg_postprocess.py +0 -52
  265. pyxlpr/ppocr/postprocess/pse_postprocess/__init__.py +0 -15
  266. pyxlpr/ppocr/postprocess/pse_postprocess/pse/__init__.py +0 -29
  267. pyxlpr/ppocr/postprocess/pse_postprocess/pse/setup.py +0 -14
  268. pyxlpr/ppocr/postprocess/pse_postprocess/pse_postprocess.py +0 -118
  269. pyxlpr/ppocr/postprocess/rec_postprocess.py +0 -654
  270. pyxlpr/ppocr/postprocess/sast_postprocess.py +0 -355
  271. pyxlpr/ppocr/tools/__init__.py +0 -14
  272. pyxlpr/ppocr/tools/eval.py +0 -83
  273. pyxlpr/ppocr/tools/export_center.py +0 -77
  274. pyxlpr/ppocr/tools/export_model.py +0 -129
  275. pyxlpr/ppocr/tools/infer/predict_cls.py +0 -151
  276. pyxlpr/ppocr/tools/infer/predict_det.py +0 -300
  277. pyxlpr/ppocr/tools/infer/predict_e2e.py +0 -169
  278. pyxlpr/ppocr/tools/infer/predict_rec.py +0 -414
  279. pyxlpr/ppocr/tools/infer/predict_system.py +0 -204
  280. pyxlpr/ppocr/tools/infer/utility.py +0 -629
  281. pyxlpr/ppocr/tools/infer_cls.py +0 -83
  282. pyxlpr/ppocr/tools/infer_det.py +0 -134
  283. pyxlpr/ppocr/tools/infer_e2e.py +0 -122
  284. pyxlpr/ppocr/tools/infer_kie.py +0 -153
  285. pyxlpr/ppocr/tools/infer_rec.py +0 -146
  286. pyxlpr/ppocr/tools/infer_table.py +0 -107
  287. pyxlpr/ppocr/tools/program.py +0 -596
  288. pyxlpr/ppocr/tools/test_hubserving.py +0 -117
  289. pyxlpr/ppocr/tools/train.py +0 -163
  290. pyxlpr/ppocr/tools/xlprog.py +0 -748
  291. pyxlpr/ppocr/utils/EN_symbol_dict.txt +0 -94
  292. pyxlpr/ppocr/utils/__init__.py +0 -24
  293. pyxlpr/ppocr/utils/dict/ar_dict.txt +0 -117
  294. pyxlpr/ppocr/utils/dict/arabic_dict.txt +0 -162
  295. pyxlpr/ppocr/utils/dict/be_dict.txt +0 -145
  296. pyxlpr/ppocr/utils/dict/bg_dict.txt +0 -140
  297. pyxlpr/ppocr/utils/dict/chinese_cht_dict.txt +0 -8421
  298. pyxlpr/ppocr/utils/dict/cyrillic_dict.txt +0 -163
  299. pyxlpr/ppocr/utils/dict/devanagari_dict.txt +0 -167
  300. pyxlpr/ppocr/utils/dict/en_dict.txt +0 -63
  301. pyxlpr/ppocr/utils/dict/fa_dict.txt +0 -136
  302. pyxlpr/ppocr/utils/dict/french_dict.txt +0 -136
  303. pyxlpr/ppocr/utils/dict/german_dict.txt +0 -143
  304. pyxlpr/ppocr/utils/dict/hi_dict.txt +0 -162
  305. pyxlpr/ppocr/utils/dict/it_dict.txt +0 -118
  306. pyxlpr/ppocr/utils/dict/japan_dict.txt +0 -4399
  307. pyxlpr/ppocr/utils/dict/ka_dict.txt +0 -153
  308. pyxlpr/ppocr/utils/dict/korean_dict.txt +0 -3688
  309. pyxlpr/ppocr/utils/dict/latin_dict.txt +0 -185
  310. pyxlpr/ppocr/utils/dict/mr_dict.txt +0 -153
  311. pyxlpr/ppocr/utils/dict/ne_dict.txt +0 -153
  312. pyxlpr/ppocr/utils/dict/oc_dict.txt +0 -96
  313. pyxlpr/ppocr/utils/dict/pu_dict.txt +0 -130
  314. pyxlpr/ppocr/utils/dict/rs_dict.txt +0 -91
  315. pyxlpr/ppocr/utils/dict/rsc_dict.txt +0 -134
  316. pyxlpr/ppocr/utils/dict/ru_dict.txt +0 -125
  317. pyxlpr/ppocr/utils/dict/ta_dict.txt +0 -128
  318. pyxlpr/ppocr/utils/dict/table_dict.txt +0 -277
  319. pyxlpr/ppocr/utils/dict/table_structure_dict.txt +0 -2759
  320. pyxlpr/ppocr/utils/dict/te_dict.txt +0 -151
  321. pyxlpr/ppocr/utils/dict/ug_dict.txt +0 -114
  322. pyxlpr/ppocr/utils/dict/uk_dict.txt +0 -142
  323. pyxlpr/ppocr/utils/dict/ur_dict.txt +0 -137
  324. pyxlpr/ppocr/utils/dict/xi_dict.txt +0 -110
  325. pyxlpr/ppocr/utils/dict90.txt +0 -90
  326. pyxlpr/ppocr/utils/e2e_metric/Deteval.py +0 -574
  327. pyxlpr/ppocr/utils/e2e_metric/polygon_fast.py +0 -83
  328. pyxlpr/ppocr/utils/e2e_utils/extract_batchsize.py +0 -87
  329. pyxlpr/ppocr/utils/e2e_utils/extract_textpoint_fast.py +0 -457
  330. pyxlpr/ppocr/utils/e2e_utils/extract_textpoint_slow.py +0 -592
  331. pyxlpr/ppocr/utils/e2e_utils/pgnet_pp_utils.py +0 -162
  332. pyxlpr/ppocr/utils/e2e_utils/visual.py +0 -162
  333. pyxlpr/ppocr/utils/en_dict.txt +0 -95
  334. pyxlpr/ppocr/utils/gen_label.py +0 -81
  335. pyxlpr/ppocr/utils/ic15_dict.txt +0 -36
  336. pyxlpr/ppocr/utils/iou.py +0 -54
  337. pyxlpr/ppocr/utils/logging.py +0 -69
  338. pyxlpr/ppocr/utils/network.py +0 -84
  339. pyxlpr/ppocr/utils/ppocr_keys_v1.txt +0 -6623
  340. pyxlpr/ppocr/utils/profiler.py +0 -110
  341. pyxlpr/ppocr/utils/save_load.py +0 -150
  342. pyxlpr/ppocr/utils/stats.py +0 -72
  343. pyxlpr/ppocr/utils/utility.py +0 -80
  344. pyxlpr/ppstructure/__init__.py +0 -13
  345. pyxlpr/ppstructure/predict_system.py +0 -187
  346. pyxlpr/ppstructure/table/__init__.py +0 -13
  347. pyxlpr/ppstructure/table/eval_table.py +0 -72
  348. pyxlpr/ppstructure/table/matcher.py +0 -192
  349. pyxlpr/ppstructure/table/predict_structure.py +0 -136
  350. pyxlpr/ppstructure/table/predict_table.py +0 -221
  351. pyxlpr/ppstructure/table/table_metric/__init__.py +0 -16
  352. pyxlpr/ppstructure/table/table_metric/parallel.py +0 -51
  353. pyxlpr/ppstructure/table/table_metric/table_metric.py +0 -247
  354. pyxlpr/ppstructure/table/tablepyxl/__init__.py +0 -13
  355. pyxlpr/ppstructure/table/tablepyxl/style.py +0 -283
  356. pyxlpr/ppstructure/table/tablepyxl/tablepyxl.py +0 -118
  357. pyxlpr/ppstructure/utility.py +0 -71
  358. pyxlpr/xlai.py +0 -10
pyxllib/ext/old.py CHANGED
@@ -1,663 +1,663 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- # @Author : 陈坤泽
4
- # @Email : 877362867@qq.com
5
- # @Date : 2018/07/12 09:32
6
-
7
-
8
- """ 一系列还未整理的旧代码
9
-
10
- 任何模块代码的第一个字符串用来写文档注释
11
-
12
- 因为util下的debuglib、textlib、filelib的功能拆分并不是特别精确,所以一般不对外开放接口
13
- 而是由util作为统一的一个大工具箱接口对外开放
14
- """
15
-
16
- import filecmp
17
- import shutil
18
- import sys
19
- import textwrap
20
- from os.path import join as pathjoin
21
- from collections import OrderedDict, Counter
22
- import base64
23
- import requests
24
-
25
- from bs4 import BeautifulSoup
26
-
27
-
28
- def ________C_文本处理________():
29
- pass
30
-
31
-
32
- def 从部门Confluence获取数据(url):
33
- cookies = getattr(从部门Confluence获取数据, 'cookies', None)
34
- if cookies: # 如果存储了cookies,尝试使用
35
- r = requests.get(url, cookies=cookies)
36
- if not cookies or not r.cookies._cookies: # 如果没有cookies或者读取失败(使用_cookies是否为空判断登陆是否成功),则重新登陆获取cookies
37
- r = requests.get('http://doc.klxuexi.org/login.action', auth=('chenkz', 'klxx11235813'))
38
- cookies = r.cookies
39
- r = requests.get(url, cookies=cookies)
40
- 从部门Confluence获取数据.cookies = cookies
41
- return r.text
42
-
43
-
44
- def ReadFromUrl(url):
45
- """从url获得文本数据
46
-
47
- 对特殊的网页有专门优化
48
- """
49
- if 'paste.ubuntu.com' in url:
50
- return read_from_ubuntu(url)
51
- elif url.startswith('http://doc.klxuexi.org'): # 这个写法主要是针对工时统计表
52
- # TODO:如果是工时表,应该做成DataFrame结构数据
53
- text = 从部门Confluence获取数据(url)
54
- soup = BeautifulSoup(text, 'lxml') # 解析网页得到soup对象
55
- content = soup.find_all(name='div', attrs={'id': 'main-content'})[0] # 提取conteng部分的内容
56
- return content.get_text('\t') # 仅获得文本信息,每项用\t隔开
57
- else:
58
- r = requests.get(url)
59
- soup = BeautifulSoup(r.text, 'lxml')
60
- return soup.get_text()
61
-
62
-
63
- def EnsureContent(ob=None, encoding='utf8'):
64
- """
65
- 未输入ob参数时,自动从控制台获取文本
66
-
67
- 输入的如果是字符串内容,则返回字符串内容
68
- 输入的如果是文件名,则读取文件的内容返回
69
- 输入的如果是url,则返回html爬取内容
70
- """
71
- # TODO: 如果输入的是一个文件指针,也能调用f.read()返回所有内容
72
- # TODO: 增加鲁棒性判断,如果输入的不是字符串类型也要有出错判断
73
-
74
- if ob is None:
75
- return sys.stdin.read() # 注意输入是按 Ctrl + D 结束
76
- elif ob.find('\n') >= 0 or len(ob) > 200: # 如果存在回车符,不用想了,直接认为是字符串
77
- return ob
78
- elif os.path.exists(ob): # 如果存在这样的文件,那就读取文件内容
79
- if ob.endswith('.pdf'): # 如果是pdf格式,则读取后转换为文本格式
80
- res = map(lambda page: page.getText('text'), fitz.open(ob))
81
- return '\n'.join(res)
82
- elif ob.endswith('.docx'):
83
- import textract
84
- text = textract.process(ob)
85
- return text.decode(encoding, errors='ignore')
86
- elif ob.endswith('.doc'):
87
- from pyxllib.ex.win32lib import XlWin32WordApplication
88
- app = XlWin32WordApplication.get_app()
89
- a = app.open_doc(ob)
90
- s = a.content
91
- a.Close()
92
- return s
93
- else: # 其他按文本格式处理
94
- if ob.endswith(r'.tex'):
95
- encoding = 'gbk' # TODO:强制转为gbk,这个后续要改
96
- with open(ob, 'r', errors='ignore', encoding=encoding) as f:
97
- # 默认编码是跟平台有关,比如windows是gbk
98
- return f.read()
99
- elif ob.startswith('http'):
100
- try:
101
- return ReadFromUrl(ob)
102
- except:
103
- # 读取失败则返回原内容
104
- return ob
105
- elif isinstance(ob, pd.DataFrame):
106
- # 还未开发
107
- pass
108
- else:
109
- # 判断不了的情况,也认为是字符串
110
- return ob
111
-
112
-
113
- ################################################################################
114
- # 文 本 处 理
115
- ################################################################################
116
-
117
-
118
- def PrintFullTable(df, *, 最后一列左对齐=False, columns=None):
119
- if isinstance(df, (list, tuple)):
120
- df = pd.DataFrame.from_records(df, columns=columns)
121
-
122
- if len(df) < 1:
123
- return
124
- """参考文档: http://pandas.pydata.org/pandas-docs/stable/options.html"""
125
- with pd.option_context('display.max_rows', None, # 没有行数限制
126
- 'display.max_columns', None, # 没有列数限制(超过列数会分行显示)
127
- 'display.width', None, # 没有列宽限制
128
- 'display.max_colwidth', 10 ** 6, # 单列宽度上限
129
- # 'display.colheader_justify', 'left', # 列标题左对齐
130
- 'display.unicode.east_asian_width', True, # 中文输出必备选项,用来控制正确的域宽
131
- ):
132
- if 最后一列左对齐: # 但是这里涉及中文的时候又会出错~~
133
- # df.iloc[:, -1] = (lambda s: s.str.ljust(s.str.len().max()))(df.iloc[:, -1]) # 最后一列左对齐
134
- def func(s):
135
- return s.str.ljust(s.str.len().max())
136
-
137
- df.iloc[:, -1] = func(df.iloc[:, -1]) # 最后一列左对齐
138
- print(df)
139
- # print(df.info())
140
-
141
-
142
- def 重定向到浏览器显示(fileName=None):
143
- """第一次执行时,必须给一个参数,代表重定向的输出文件名
144
-
145
- 第二次执行时,不要输入参数,此时会弹出chrome.exe显示已保存的所有输出内容
146
- """
147
- if fileName:
148
- 重定向到浏览器显示.fileName = fileName
149
- 重定向到浏览器显示.oldTarget = sys.stdout
150
- sys.stdout = open(fileName, 'w')
151
- else: # 如果没写参数,则显示
152
- sys.stdout = 重定向到浏览器显示.oldTarget
153
- subprocess.run(['chrome.exe', 重定向到浏览器显示.fileName])
154
-
155
-
156
- def regular_cut(old_str, pattern, flags=0):
157
- r"""返回第1个参数是新的new_str,去掉了被提取的元素
158
- 返回第2个参数是提取出来的数据列表
159
-
160
- >>> regular_cut('abc123de4f', r'\d+')
161
- ('abcdef', ['123', '4'])
162
- >>> regular_cut('abc123de4f', r'c(\d+)')
163
- ('abde4f', ['123'])
164
- """
165
- new_str = re.sub(pattern, '', old_str, flags=flags)
166
- elements = re.findall(pattern, old_str, flags=flags)
167
- return new_str, elements
168
-
169
-
170
- def research(pattern, string):
171
- """ .能匹配所有字符
172
- 返回第一个匹配的字符串(的group(1)),结果会去掉左右空白
173
- 如果找不到则返回空字符串
174
- """
175
- m = re.search(pattern, string, flags=re.DOTALL)
176
- return m.group(1).strip() if m else ''
177
-
178
-
179
- def ________D_文件目录相关函数________():
180
- """"""
181
- pass
182
-
183
-
184
- ################################################################################
185
- ### 目录相关函数
186
- ################################################################################
187
-
188
-
189
- def SetWkDir(wkDir=None, key=None):
190
- r"""用过的工作目录存在字典wkdirs {int:string},原始目录用0索引,上一个目录用-1索引
191
- 新设的目录可以添加自己的索引key
192
-
193
- SetWkDir(0)
194
- SetWkDir('word')
195
- SetWkDir(0)
196
- SetWkDir(-1)
197
- """
198
- wkDir = str(wkDir)
199
- SetWkDir.wkdirs = getattr(SetWkDir, 'wkdirs', {'0': os.getcwd(), '-1': os.getcwd()})
200
- wkdirs = SetWkDir.wkdirs
201
- lastWkDir = os.getcwd()
202
-
203
- if wkDir in wkdirs:
204
- os.chdir(wkdirs[wkDir])
205
- elif wkDir == '': # 如果输入空字符串,则返回当前工作目录(这在使用os.path.dirname('a.tex')时是会发生的)
206
- return os.getcwd()
207
- else:
208
- os.chdir(wkDir) # 切换到目标工作目录
209
- if key: # 如果输入了key,则存储当前工作目录
210
- wkdirs[key] = wkDir
211
-
212
- wkdirs[-1] = lastWkDir
213
- return lastWkDir # 返回切换前的目录
214
-
215
-
216
- def SmartCopyFiles(files, inFolder, outFolder):
217
- """将files里的文件移到folder目录里,如果folder里已经存在对应文件则自动进行备份"""
218
- inFd = File(inFolder)
219
- outFd = File(outFolder)
220
-
221
- for file in files:
222
- inFile = inFd / file
223
- if not inFile.exists(): # 如果原目录里并不含有该文件则continue
224
- continue
225
- outFile = outFd / file
226
- if outFile.exists():
227
- if filecmp.cmp(inFile, outFile):
228
- continue # 如果两个文件是相同的,不用操作,可以直接处理下一个
229
- else:
230
- File(outFile).backup() # 如果不相同,则对outFile进行备份
231
- shutil.copy2(inFile, outFile)
232
- File(outFile).backup() # 对拷贝过来的文件也提前做好备份
233
-
234
-
235
- def MyMove(folder1, folder2):
236
- """将目录1里的文件复制到目录2,如果目录2已存在文件,则对其调用备份"""
237
- pass
238
-
239
-
240
- def 多规则字符串筛选(列表, glob筛选=None, *, 正则筛选=None, 指定名筛选=None, 去除备份文件=False):
241
- """该函数主要供文件处理使用,其它字符串算法慎用"""
242
- if glob筛选:
243
- 列表 = list(filter(lambda x: File(x).match(glob筛选), 列表))
244
-
245
- # 只挑选出满足正则条件的文件名(目录名)
246
- if 正则筛选:
247
- 列表 = list(filter(lambda x: re.match(正则筛选, x, flags=re.IGNORECASE), 列表))
248
-
249
- if 指定名筛选:
250
- 列表 = list(filter(lambda x: x in 指定名筛选, 列表))
251
-
252
- if 去除备份文件:
253
- 列表 = list(filter(lambda x: not File(x).backup_time, 列表))
254
-
255
- return 列表
256
-
257
-
258
- def 递归删除空目录(rootPath):
259
- fd = CBaseFolder(rootPath)
260
- for f in fd.Folders():
261
- d = CBaseFolder(pathjoin(rootPath, f))
262
- if d.大小():
263
- 递归删除空目录(d.name)
264
- else:
265
- d.删除()
266
-
267
-
268
- class CBaseFolder(object):
269
- def __init__(self, s='.'):
270
- """TODO:应该支持'a/*.eps'这种操作,指定目录的同时,也进行了文件筛选"""
271
- self.path = GetFullPathClass(s)
272
- self.name = str(self.path)
273
- self.files = self.Files()
274
- if os.path.exists(self.name):
275
- self.folderStats = os.stat(s)
276
-
277
- def Files(self, glob筛选=None, *, 正则筛选=None, 指定名筛选=None, 去除备份文件=False):
278
- """注意:正则规则和一般的文件匹配规则是不一样的!
279
- 比如glob中的'*.log',在正则中应该谢伟'.*[.]log'
280
-
281
- 使用举例:
282
- f.Files('*.tex', 正则筛选=r'ch[a-zA-Z]*[.]tex', 指定名筛选 = ('chePre.tex', 'cheRev.tex'))
283
- """
284
- if not self:
285
- return list()
286
-
287
- ls = os.listdir(self.name)
288
- ls = list(filter(self.IsFile, ls))
289
- files = 多规则字符串筛选(ls, glob筛选, 正则筛选=正则筛选, 指定名筛选=指定名筛选, 去除备份文件=去除备份文件)
290
- files = natural_sort(files)
291
- return files
292
-
293
- def 递归获取文件(self, 过滤器=lambda x: True):
294
- """过滤器输入一个函数,文件名要满足指定条件才会被提取"""
295
- for f in list(filter(过滤器, self.files)): yield pathjoin(self.path, f)
296
- for folder in self.Folders():
297
- try: # 有些系统目录会读取不了
298
- fd = CBaseFolder(pathjoin(self.name, folder))
299
- for f in fd.递归获取文件(过滤器): yield f
300
- except:
301
- continue
302
-
303
- def Folders(self, glob筛选=None, *, 正则筛选=None, 指定名筛选=None, 去除备份文件=False):
304
- ls = os.listdir(self.name)
305
- ls = list(filter(self.IsFolder, ls))
306
- return 多规则字符串筛选(ls, glob筛选, 正则筛选=正则筛选, 指定名筛选=指定名筛选, 去除备份文件=去除备份文件)
307
-
308
- def IsFile(self, f):
309
- return os.path.isfile(os.path.join(self.name, f))
310
-
311
- def IsFolder(self, f):
312
- if f in ('$RECYCLE.BIN', 'Recovery', 'System Volume Information'): # 过滤掉无需访问的目录
313
- return False
314
- else:
315
- return os.path.isdir(os.path.join(self.name, f))
316
-
317
- def FilesRename(self, origin, target, *, 目标目录=None):
318
- """使用正则规则匹配文件名,并重命名"""
319
- files = self.Files(正则筛选=origin)
320
- if not 目标目录: # 如果没有设置目标目录,则以该类所在目录为准
321
- 目标目录 = self.name
322
- for fn in files:
323
- f = File(os.path.join(self.name, fn))
324
- 目标名称 = re.sub(origin, target, fn, flags=re.IGNORECASE)
325
- f.rename(os.path.join(目标目录, 目标名称))
326
-
327
- def 递归输出文件列表(self, *, 当前层级=0, 控制宽度=None):
328
- """占秋意见:可以根据扩展名简化输出内容"""
329
- fileString = ', '.join(self.files)
330
- if isinstance(控制宽度, int):
331
- fileString = textwrap.shorten(fileString, 控制宽度, placeholder='...')
332
- s = '{}【{}】({}): {}'.format('\t' * 当前层级, self.path.stem, len(self.files), fileString)
333
- print(s)
334
- for folder in self.Folders():
335
- try: # 有些系统目录会读取不了
336
- fd = CBaseFolder(pathjoin(self.name, folder))
337
- fd.递归输出文件列表(当前层级=当前层级 + 1, 控制宽度=控制宽度)
338
- except:
339
- continue
340
-
341
- def 大小(self):
342
- return File(self.name).size
343
-
344
- def 删除(self):
345
- shutil.rmtree(self.name, ignore_errors=True)
346
-
347
- def __bool__(self):
348
- return os.path.isdir(str(self.path))
349
-
350
- def __str__(self):
351
- return self.name
352
-
353
-
354
- def 自定义正则规则转为标准正则表达式(s):
355
- s = s.replace('?', r'[\u4e00-\u9fa5]') # 中文问号匹配任意一个中文字符
356
- return s
357
-
358
-
359
- def 文件搜索匹配(源目录, 自定义正则规则, *, 目标类型=('文件', '目录')):
360
- """ 目标类型=('文件','目录') """
361
- 匹配文件 = list()
362
- 源目录前缀长度 = len(源目录)
363
- 正则规则 = 自定义正则规则转为标准正则表达式(自定义正则规则)
364
- 所有目录 = tuple(os.walk(源目录))
365
- for 当前目录名, 包含目录, 包含文件 in 所有目录:
366
- parts = File(当前目录名).parts
367
- if '.git' in parts or '$RECYCLE.BIN' in parts: # 去掉'.git'这个备份目录,'$RECYCLE.BIN'这个不知啥鬼目录
368
- continue
369
- 相对目录 = 当前目录名[源目录前缀长度 + 1:]
370
- if '目录' in 目标类型:
371
- if re.search(正则规则, 相对目录):
372
- 匹配文件.append(相对目录)
373
- if '文件' in 目标类型:
374
- for 文件 in 包含文件:
375
- 相对路径 = os.path.join(相对目录, 文件)
376
- if re.search(正则规则, 相对路径):
377
- 匹配文件.append(相对路径)
378
- return natural_sort(匹配文件)
379
-
380
-
381
- def 文件复制(源目录, 自定义正则规则, 目标目录, 新正则名称, *, 目标类型=('文件',)):
382
- """ 目标类型=('文件','目录') """
383
- 匹配文件 = 文件搜索匹配(源目录, 自定义正则规则, 目标类型=目标类型)
384
- # 获得匹配文件后,需要从后往前改,否则产生连锁反应会索引不到
385
-
386
-
387
- def 文件重命名(源目录, 自定义正则规则, 新正则名称, *, 目标类型=('文件',), 目标目录=None, 调试=True, 输出=True, 覆盖操作=False):
388
- """因为这个操作风险非常大,所以默认情况下是调试模式,必须手动指定进入非调试模式才会进行实际工作
389
-
390
- 使用示例:文件重命名(r'D:\2017LaTeX\B暑假教材\高数\高一教师版 - 测试\figs - 副本',
391
- r'^(.*?)-eps-converted-to[.]png', r'\1.png', 调试=False)
392
- """
393
- ls = list()
394
- 匹配文件 = 文件搜索匹配(源目录, 自定义正则规则, 目标类型=目标类型)
395
- 正则规则 = 自定义正则规则转为标准正则表达式(自定义正则规则)
396
- if not 目标目录:
397
- 目标目录 = 源目录
398
- for f in reversed(匹配文件):
399
- f2 = re.sub(正则规则, 新正则名称, f)
400
- ls.append([f, f2])
401
- if not 调试:
402
- targetName = os.path.join(目标目录, f2)
403
- f3 = File(targetName)
404
- if f3:
405
- print('文件已存在:', f3.name)
406
- if 覆盖操作:
407
- f3.delete()
408
- os.rename(os.path.join(源目录, f), targetName)
409
- else:
410
- os.rename(os.path.join(源目录, f), targetName)
411
-
412
- df = pd.DataFrame.from_records(ls, columns=('原文件名', '目标文件名'))
413
- if 输出:
414
- PrintFullTable(df)
415
- return df
416
-
417
-
418
- # def 目录下查找文本(目录, 文件名筛选, 目标文本):
419
- # ls = 文件搜索匹配(目录, 文件名筛选, 目标类型=('文件',))
420
- # ls = list(filter(lambda x: Path(x).backup_time == '', ls)) # 去除备份文件
421
- # ls = natural_sort(ls)
422
- # 文件名 = list()
423
- # 出现次数 = list()
424
- # 行号 = list()
425
- # for i, fileName in enumerate(ls):
426
- # cl = ContentLine(pathjoin(目录, fileName))
427
- # lines = cl.regular_search(目标文本)
428
- # if lines:
429
- # 文件名.append(fileName)
430
- # 出现次数.append(len(lines))
431
- # 行号.append(str(lines))
432
- #
433
- # pf = pd.DataFrame({'文件名': 文件名, '出现次数': 出现次数, '行号': 行号}, columns=['文件名', '出现次数', '行号'])
434
- # pf.sort_values(by=['出现次数'], ascending=False, inplace=True)
435
- # PrintFullTable(pf, 最后一列左对齐=True)
436
- # return pf
437
-
438
-
439
- def 目录下查找文本(目录, 文件名筛选, 目标文本, *, 模式='表格'):
440
- """
441
- 表格模式:统计每个文件中出现的总次数
442
- 行文本模式:显示所有匹配的行文本
443
- """
444
- ls = 文件搜索匹配(目录, 文件名筛选, 目标类型=('文件',))
445
- ls = list(filter(lambda x: File(x).backup_time == '', ls)) # 去除备份文件
446
- ls = natural_sort(ls)
447
- if 模式 == '表格':
448
- table = list()
449
- for i, fileName in enumerate(ls):
450
- cl = ContentLine(pathjoin(目录, fileName))
451
- lines = cl.regular_search(目标文本)
452
- if lines:
453
- table.append((fileName, len(lines), refine_digits_set(lines)))
454
-
455
- pf = pd.DataFrame.from_records(table, columns=('文件名', '出现次数', '行号'))
456
- for i in range(len(pf)):
457
- pf['出现次数'][i] = int(pf['出现次数'][i])
458
- pf.sort_values(by=['出现次数'], ascending=False, inplace=True)
459
- PrintFullTable(pf, 最后一列左对齐=True)
460
- return pf
461
- elif 模式 == '行文本':
462
- for i, fileName in enumerate(ls):
463
- cl = ContentLine(pathjoin(目录, fileName))
464
- lines = cl.regular_search(目标文本)
465
- if lines:
466
- print()
467
- # print(fileName) # 不输出根目录版本
468
- print(pathjoin(目录, fileName)) # 输出根目录版本
469
- print(cl.lines_content(lines))
470
- else:
471
- raise TypeError
472
-
473
-
474
- def 目录下统计单词出现频数(目录, 文件名筛选, 目标文本=r'(\\?[a-zA-Z]+)(?![a-zA-Z])'):
475
- """默认会找所有单词,以及tex命令"""
476
- ls = 文件搜索匹配(目录, 文件名筛选, 目标类型=('文件',))
477
- s = list()
478
- for fileName in [f for f in ls if not File(f).backup_time]: # 去除备份文件
479
- c = File(pathjoin(目录, fileName)).read()
480
- s.append(c)
481
- s = '\n'.join(s)
482
-
483
- # ls = re.findall(r'(?<=\\)([a-zA-Z]+)(?![a-zA-Z])', s) # 统计tex命令数量
484
- # ls = re.findall(r'([a-zA-Z]+)(?![a-zA-Z])', s) # 统计单词次数
485
- # ls = re.findall(r'(\\?[a-zA-Z]+)(?![a-zA-Z])', s) # tex和普通单词综合性搜索
486
- ls = re.findall(目标文本, s)
487
- d = OrderedDict(sorted(Counter(ls).items(), key=lambda t: -t[1]))
488
- pf = pd.DataFrame({'关键字': list(d.keys()), '出现次数': list(d.values())}, columns=['关键字', '出现次数'])
489
- PrintFullTable(pf)
490
- return pf
491
-
492
-
493
- def GetFullPathClass(s):
494
- """如果输入的是相对路径,会解析为绝对路径"""
495
- # p = Path(s).resolve() # 奕本的电脑这句话运行不了
496
- p = File(s)
497
- if not s.startswith('\\') and not p.drive:
498
- p = File.cwd() / p
499
- return p
500
-
501
-
502
- ____other = """"""
503
-
504
- mydecrypt = base64.b64decode
505
-
506
-
507
- class LengthFormatter:
508
- """ 长度换算类,可以在允许浮点小误差的场景使用
509
- TODO 需要精确运算也是可以的,那就要用分数类来存储底层值了
510
-
511
- # 默认标准长度是mm,所以初始化一个233数字,就等于用233mm初始化
512
- >>> LengthFormatter(233).cm # 然后可以转化为cm,计算厘米单位下的长度值
513
- 23.3
514
- >>> LengthFormatter('233pt') # 可以用带单位的字符串
515
- 81.78mm
516
- >>> LengthFormatter('233.45 pt') # 支持小数、有空格等格式
517
- 81.94mm
518
-
519
- 应用举例:把长度超过12cm的hspace都限制在12cm以内
520
- >> s = NestEnv(s).latexcmd1('hspace').bracket('{', inner=True).\
521
- replace(lambda x: '12cm' if LengthFormatter(x).cm > 12 else x)
522
- """
523
-
524
- # 所有其他单位长度与参照长度mm之间比例关系
525
- ratio = {'pt': 0.351, # 点
526
- 'bp': 0.353, # 大点,≈1pt
527
- 'dd': 0.376, # 迪多,=1.07pt
528
- 'pc': 4.218, # 派卡,=12pt
529
- 'sp': 1 / 65536, # 定标点,65536sp=1pt
530
- 'cm': 10, # 厘米
531
- 'cc': 4.513, # 西塞罗
532
- 'in': 25.4, # 英寸,=72.27pt
533
- 'em': 18, # 1em≈当前字体中M的宽度,在正文12pt情况下,一般为18pt
534
- 'ex': 12, # 1ex≈当前字体中x的高度,暂按12pt处理
535
- }
536
-
537
- def __init__(self, v=0):
538
- if isinstance(v, (int, float)):
539
- self.__dict__['mm'] = v
540
- elif isinstance(v, str):
541
- m = re.match(r'(-?\d+(?:\.\d*)?)\s*(' + '|'.join(list(self.ratio.keys()) + ['mm']) + ')$', v)
542
- if not m: raise ValueError(f'不存在的长度单位类型:{v}')
543
- self.__dict__['mm'] = 0
544
- self.__setitem__(m.group(2), float(m.group(1)))
545
- else:
546
- raise ValueError(f'不存在的长度单位类型:{v}')
547
-
548
- def __repr__(self):
549
- return '{:.2f}mm'.format(self.__dict__['mm'])
550
-
551
- def __getattr__(self, key):
552
- if key in self.ratio.keys():
553
- return self.__dict__['mm'] / self.ratio[key]
554
- else:
555
- raise ValueError(f'不存在的长度单位类型:{key}')
556
-
557
- def __setitem__(self, key, value):
558
- if key == 'mm':
559
- self.__dict__['mm'] = value
560
- elif key in self.ratio.keys():
561
- self.__dict__['mm'] = value * self.ratio[key]
562
- else:
563
- raise ValueError(f'不存在的长度单位类型:{key}')
564
-
565
-
566
- ____image = """
567
- 暂时还没空整理的一些图片功能
568
- """
569
-
570
-
571
- def 缩放目录下所有png图片(folder, rate=120):
572
- """rate可以控制缩放比例,正常是100
573
- 再乘120是不想缩放太多,理论上乘100是正常比例
574
-
575
- 旧函数名:缩放目录下所有png图片
576
- """
577
- fd = Dir(folder)
578
- for f in fd.select_files('*.png'):
579
- try:
580
- im = Image.open(str(f))
581
- if 'dpi' in im.info:
582
- if im.info['dpi'][0] in (305, 610): # 这个是magick转换过来的特殊值,不能缩放
583
- continue # 180920周四,610是为欧龙加的,欧龙双师需要设置-density 240
584
- # print(files, im.info) # dpi: 600
585
- # print(查看图片的Exif信息(im))
586
- s = list(im.size)
587
- s[0] = int(s[0] / im.info['dpi'][0] * rate)
588
- s[1] = int(s[1] / im.info['dpi'][1] * rate)
589
- im = im.resize(s, Image.ANTIALIAS)
590
- im.save(str(f))
591
- except:
592
- print('无法处理图片:', f)
593
- continue
594
-
595
-
596
- def 缩放目录下所有png图片2(folder, scale=1.0):
597
- """rate可以控制缩放比例,正常是100
598
- 再乘120是不想缩放太多,理论上乘100是正常比例
599
-
600
- 旧函数名:缩放目录下所有png图片2
601
- """
602
- fd = Dir(folder)
603
- for f in fd.select_files('*.png'):
604
- im = Image.open(str(f))
605
- s = list(im.size)
606
- s[0] = int(s[0] * scale)
607
- s[1] = int(s[1] * scale)
608
- im = im.resize(s, Image.ANTIALIAS)
609
- im.save(str(f))
610
-
611
-
612
- def 查看目录下png图片信息(folder):
613
- """
614
- 旧函数名:查看目录下png图片信息
615
- """
616
- fd = Dir(folder)
617
- ls = list()
618
- for f in fd.select_files('*.png'):
619
- im = Image.open(str(f))
620
- d0, d1 = im.info['dpi'] if 'dpi' in im.info else ('', '')
621
- # 处理eps格式
622
- epsFile = f.with_suffix('.eps')
623
- if epsFile:
624
- epsSize, epsIm = epsFile.大小(), Image.open(epsFile.name)
625
- boundingBox = epsIm.info['BoundingBox'].replace(' ', ',') if 'BoundingBox' in epsIm.info else ''
626
- else:
627
- epsSize, boundingBox = '', ''
628
- # 处理pdf格式
629
- pdfFile = File(f.name[:-4] + '-eps-converted-to.pdf')
630
- pdfSize = pdfFile.size if pdfFile else ''
631
- # 存储到列表
632
- ls.append((f, im.size[0], im.size[1], d0, d1,
633
- f.size, f.mtime.strftime(' %y%m%d-%H%M%S'),
634
- epsSize, boundingBox, pdfSize))
635
- df = pd.DataFrame.from_records(ls,
636
- columns=('fileName', 'width', 'height', 'dpi_w', 'dpi_h', 'size', 'time', 'epsSize',
637
- 'boundingBox', 'pdfSize'))
638
- with pd.option_context('display.max_colwidth', -1, 'display.max_columns', 20,
639
- 'display.width', 200): # 上下文控制格式
640
- print(df)
641
- return df
642
-
643
-
644
- def make_color_transparent(image, color, thresh2=0):
645
- """ 将指定颜色转为透明
646
- https://stackoverflow.com/questions/765736/using-pil-to-make-all-white-pixels-transparent/765829
647
-
648
- 旧函数名:MakeColorTransparent
649
- """
650
- from PIL import ImageMath
651
-
652
- def distance2(a, b):
653
- return (a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]) + (a[2] - b[2]) * (a[2] - b[2])
654
-
655
- image = image.convert("RGBA")
656
- red, green, blue, alpha = image.split()
657
- image.putalpha(ImageMath.eval("""convert(((((t - d(c, (r, g, b))) >> 31) + 1) ^ 1) * a, 'L')""",
658
- t=thresh2, d=distance2, c=color, r=red, g=green, b=blue, a=alpha))
659
- return image
660
-
661
-
662
- if __name__ == '__main__':
663
- print('测试')
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # @Author : 陈坤泽
4
+ # @Email : 877362867@qq.com
5
+ # @Date : 2018/07/12 09:32
6
+
7
+
8
+ """ 一系列还未整理的旧代码
9
+
10
+ 任何模块代码的第一个字符串用来写文档注释
11
+
12
+ 因为util下的debuglib、textlib、filelib的功能拆分并不是特别精确,所以一般不对外开放接口
13
+ 而是由util作为统一的一个大工具箱接口对外开放
14
+ """
15
+
16
+ import filecmp
17
+ import shutil
18
+ import sys
19
+ import textwrap
20
+ from os.path import join as pathjoin
21
+ from collections import OrderedDict, Counter
22
+ import base64
23
+ import requests
24
+
25
+ from bs4 import BeautifulSoup
26
+
27
+
28
+ def ________C_文本处理________():
29
+ pass
30
+
31
+
32
+ def 从部门Confluence获取数据(url):
33
+ cookies = getattr(从部门Confluence获取数据, 'cookies', None)
34
+ if cookies: # 如果存储了cookies,尝试使用
35
+ r = requests.get(url, cookies=cookies)
36
+ if not cookies or not r.cookies._cookies: # 如果没有cookies或者读取失败(使用_cookies是否为空判断登陆是否成功),则重新登陆获取cookies
37
+ r = requests.get('http://doc.klxuexi.org/login.action', auth=('chenkz', 'klxx11235813'))
38
+ cookies = r.cookies
39
+ r = requests.get(url, cookies=cookies)
40
+ 从部门Confluence获取数据.cookies = cookies
41
+ return r.text
42
+
43
+
44
+ def ReadFromUrl(url):
45
+ """从url获得文本数据
46
+
47
+ 对特殊的网页有专门优化
48
+ """
49
+ if 'paste.ubuntu.com' in url:
50
+ return read_from_ubuntu(url)
51
+ elif url.startswith('http://doc.klxuexi.org'): # 这个写法主要是针对工时统计表
52
+ # TODO:如果是工时表,应该做成DataFrame结构数据
53
+ text = 从部门Confluence获取数据(url)
54
+ soup = BeautifulSoup(text, 'lxml') # 解析网页得到soup对象
55
+ content = soup.find_all(name='div', attrs={'id': 'main-content'})[0] # 提取conteng部分的内容
56
+ return content.get_text('\t') # 仅获得文本信息,每项用\t隔开
57
+ else:
58
+ r = requests.get(url)
59
+ soup = BeautifulSoup(r.text, 'lxml')
60
+ return soup.get_text()
61
+
62
+
63
+ def EnsureContent(ob=None, encoding='utf8'):
64
+ """
65
+ 未输入ob参数时,自动从控制台获取文本
66
+
67
+ 输入的如果是字符串内容,则返回字符串内容
68
+ 输入的如果是文件名,则读取文件的内容返回
69
+ 输入的如果是url,则返回html爬取内容
70
+ """
71
+ # TODO: 如果输入的是一个文件指针,也能调用f.read()返回所有内容
72
+ # TODO: 增加鲁棒性判断,如果输入的不是字符串类型也要有出错判断
73
+
74
+ if ob is None:
75
+ return sys.stdin.read() # 注意输入是按 Ctrl + D 结束
76
+ elif ob.find('\n') >= 0 or len(ob) > 200: # 如果存在回车符,不用想了,直接认为是字符串
77
+ return ob
78
+ elif os.path.exists(ob): # 如果存在这样的文件,那就读取文件内容
79
+ if ob.endswith('.pdf'): # 如果是pdf格式,则读取后转换为文本格式
80
+ res = map(lambda page: page.getText('text'), fitz.open(ob))
81
+ return '\n'.join(res)
82
+ elif ob.endswith('.docx'):
83
+ import textract
84
+ text = textract.process(ob)
85
+ return text.decode(encoding, errors='ignore')
86
+ elif ob.endswith('.doc'):
87
+ from pyxllib.ex.win32lib import XlWin32WordApplication
88
+ app = XlWin32WordApplication.get_app()
89
+ a = app.open_doc(ob)
90
+ s = a.content
91
+ a.Close()
92
+ return s
93
+ else: # 其他按文本格式处理
94
+ if ob.endswith(r'.tex'):
95
+ encoding = 'gbk' # TODO:强制转为gbk,这个后续要改
96
+ with open(ob, 'r', errors='ignore', encoding=encoding) as f:
97
+ # 默认编码是跟平台有关,比如windows是gbk
98
+ return f.read()
99
+ elif ob.startswith('http'):
100
+ try:
101
+ return ReadFromUrl(ob)
102
+ except:
103
+ # 读取失败则返回原内容
104
+ return ob
105
+ elif isinstance(ob, pd.DataFrame):
106
+ # 还未开发
107
+ pass
108
+ else:
109
+ # 判断不了的情况,也认为是字符串
110
+ return ob
111
+
112
+
113
+ ################################################################################
114
+ # 文 本 处 理
115
+ ################################################################################
116
+
117
+
118
+ def PrintFullTable(df, *, 最后一列左对齐=False, columns=None):
119
+ if isinstance(df, (list, tuple)):
120
+ df = pd.DataFrame.from_records(df, columns=columns)
121
+
122
+ if len(df) < 1:
123
+ return
124
+ """参考文档: http://pandas.pydata.org/pandas-docs/stable/options.html"""
125
+ with pd.option_context('display.max_rows', None, # 没有行数限制
126
+ 'display.max_columns', None, # 没有列数限制(超过列数会分行显示)
127
+ 'display.width', None, # 没有列宽限制
128
+ 'display.max_colwidth', 10 ** 6, # 单列宽度上限
129
+ # 'display.colheader_justify', 'left', # 列标题左对齐
130
+ 'display.unicode.east_asian_width', True, # 中文输出必备选项,用来控制正确的域宽
131
+ ):
132
+ if 最后一列左对齐: # 但是这里涉及中文的时候又会出错~~
133
+ # df.iloc[:, -1] = (lambda s: s.str.ljust(s.str.len().max()))(df.iloc[:, -1]) # 最后一列左对齐
134
+ def func(s):
135
+ return s.str.ljust(s.str.len().max())
136
+
137
+ df.iloc[:, -1] = func(df.iloc[:, -1]) # 最后一列左对齐
138
+ print(df)
139
+ # print(df.info())
140
+
141
+
142
+ def 重定向到浏览器显示(fileName=None):
143
+ """第一次执行时,必须给一个参数,代表重定向的输出文件名
144
+
145
+ 第二次执行时,不要输入参数,此时会弹出chrome.exe显示已保存的所有输出内容
146
+ """
147
+ if fileName:
148
+ 重定向到浏览器显示.fileName = fileName
149
+ 重定向到浏览器显示.oldTarget = sys.stdout
150
+ sys.stdout = open(fileName, 'w')
151
+ else: # 如果没写参数,则显示
152
+ sys.stdout = 重定向到浏览器显示.oldTarget
153
+ subprocess.run(['chrome.exe', 重定向到浏览器显示.fileName])
154
+
155
+
156
+ def regular_cut(old_str, pattern, flags=0):
157
+ r"""返回第1个参数是新的new_str,去掉了被提取的元素
158
+ 返回第2个参数是提取出来的数据列表
159
+
160
+ >>> regular_cut('abc123de4f', r'\d+')
161
+ ('abcdef', ['123', '4'])
162
+ >>> regular_cut('abc123de4f', r'c(\d+)')
163
+ ('abde4f', ['123'])
164
+ """
165
+ new_str = re.sub(pattern, '', old_str, flags=flags)
166
+ elements = re.findall(pattern, old_str, flags=flags)
167
+ return new_str, elements
168
+
169
+
170
+ def research(pattern, string):
171
+ """ .能匹配所有字符
172
+ 返回第一个匹配的字符串(的group(1)),结果会去掉左右空白
173
+ 如果找不到则返回空字符串
174
+ """
175
+ m = re.search(pattern, string, flags=re.DOTALL)
176
+ return m.group(1).strip() if m else ''
177
+
178
+
179
+ def ________D_文件目录相关函数________():
180
+ """"""
181
+ pass
182
+
183
+
184
+ ################################################################################
185
+ ### 目录相关函数
186
+ ################################################################################
187
+
188
+
189
+ def SetWkDir(wkDir=None, key=None):
190
+ r"""用过的工作目录存在字典wkdirs {int:string},原始目录用0索引,上一个目录用-1索引
191
+ 新设的目录可以添加自己的索引key
192
+
193
+ SetWkDir(0)
194
+ SetWkDir('word')
195
+ SetWkDir(0)
196
+ SetWkDir(-1)
197
+ """
198
+ wkDir = str(wkDir)
199
+ SetWkDir.wkdirs = getattr(SetWkDir, 'wkdirs', {'0': os.getcwd(), '-1': os.getcwd()})
200
+ wkdirs = SetWkDir.wkdirs
201
+ lastWkDir = os.getcwd()
202
+
203
+ if wkDir in wkdirs:
204
+ os.chdir(wkdirs[wkDir])
205
+ elif wkDir == '': # 如果输入空字符串,则返回当前工作目录(这在使用os.path.dirname('a.tex')时是会发生的)
206
+ return os.getcwd()
207
+ else:
208
+ os.chdir(wkDir) # 切换到目标工作目录
209
+ if key: # 如果输入了key,则存储当前工作目录
210
+ wkdirs[key] = wkDir
211
+
212
+ wkdirs[-1] = lastWkDir
213
+ return lastWkDir # 返回切换前的目录
214
+
215
+
216
+ def SmartCopyFiles(files, inFolder, outFolder):
217
+ """将files里的文件移到folder目录里,如果folder里已经存在对应文件则自动进行备份"""
218
+ inFd = File(inFolder)
219
+ outFd = File(outFolder)
220
+
221
+ for file in files:
222
+ inFile = inFd / file
223
+ if not inFile.exists(): # 如果原目录里并不含有该文件则continue
224
+ continue
225
+ outFile = outFd / file
226
+ if outFile.exists():
227
+ if filecmp.cmp(inFile, outFile):
228
+ continue # 如果两个文件是相同的,不用操作,可以直接处理下一个
229
+ else:
230
+ File(outFile).backup() # 如果不相同,则对outFile进行备份
231
+ shutil.copy2(inFile, outFile)
232
+ File(outFile).backup() # 对拷贝过来的文件也提前做好备份
233
+
234
+
235
+ def MyMove(folder1, folder2):
236
+ """将目录1里的文件复制到目录2,如果目录2已存在文件,则对其调用备份"""
237
+ pass
238
+
239
+
240
+ def 多规则字符串筛选(列表, glob筛选=None, *, 正则筛选=None, 指定名筛选=None, 去除备份文件=False):
241
+ """该函数主要供文件处理使用,其它字符串算法慎用"""
242
+ if glob筛选:
243
+ 列表 = list(filter(lambda x: File(x).match(glob筛选), 列表))
244
+
245
+ # 只挑选出满足正则条件的文件名(目录名)
246
+ if 正则筛选:
247
+ 列表 = list(filter(lambda x: re.match(正则筛选, x, flags=re.IGNORECASE), 列表))
248
+
249
+ if 指定名筛选:
250
+ 列表 = list(filter(lambda x: x in 指定名筛选, 列表))
251
+
252
+ if 去除备份文件:
253
+ 列表 = list(filter(lambda x: not File(x).backup_time, 列表))
254
+
255
+ return 列表
256
+
257
+
258
+ def 递归删除空目录(rootPath):
259
+ fd = CBaseFolder(rootPath)
260
+ for f in fd.Folders():
261
+ d = CBaseFolder(pathjoin(rootPath, f))
262
+ if d.大小():
263
+ 递归删除空目录(d.name)
264
+ else:
265
+ d.删除()
266
+
267
+
268
+ class CBaseFolder(object):
269
+ def __init__(self, s='.'):
270
+ """TODO:应该支持'a/*.eps'这种操作,指定目录的同时,也进行了文件筛选"""
271
+ self.path = GetFullPathClass(s)
272
+ self.name = str(self.path)
273
+ self.files = self.Files()
274
+ if os.path.exists(self.name):
275
+ self.folderStats = os.stat(s)
276
+
277
+ def Files(self, glob筛选=None, *, 正则筛选=None, 指定名筛选=None, 去除备份文件=False):
278
+ """注意:正则规则和一般的文件匹配规则是不一样的!
279
+ 比如glob中的'*.log',在正则中应该谢伟'.*[.]log'
280
+
281
+ 使用举例:
282
+ f.Files('*.tex', 正则筛选=r'ch[a-zA-Z]*[.]tex', 指定名筛选 = ('chePre.tex', 'cheRev.tex'))
283
+ """
284
+ if not self:
285
+ return list()
286
+
287
+ ls = os.listdir(self.name)
288
+ ls = list(filter(self.IsFile, ls))
289
+ files = 多规则字符串筛选(ls, glob筛选, 正则筛选=正则筛选, 指定名筛选=指定名筛选, 去除备份文件=去除备份文件)
290
+ files = natural_sort(files)
291
+ return files
292
+
293
+ def 递归获取文件(self, 过滤器=lambda x: True):
294
+ """过滤器输入一个函数,文件名要满足指定条件才会被提取"""
295
+ for f in list(filter(过滤器, self.files)): yield pathjoin(self.path, f)
296
+ for folder in self.Folders():
297
+ try: # 有些系统目录会读取不了
298
+ fd = CBaseFolder(pathjoin(self.name, folder))
299
+ for f in fd.递归获取文件(过滤器): yield f
300
+ except:
301
+ continue
302
+
303
+ def Folders(self, glob筛选=None, *, 正则筛选=None, 指定名筛选=None, 去除备份文件=False):
304
+ ls = os.listdir(self.name)
305
+ ls = list(filter(self.IsFolder, ls))
306
+ return 多规则字符串筛选(ls, glob筛选, 正则筛选=正则筛选, 指定名筛选=指定名筛选, 去除备份文件=去除备份文件)
307
+
308
+ def IsFile(self, f):
309
+ return os.path.isfile(os.path.join(self.name, f))
310
+
311
+ def IsFolder(self, f):
312
+ if f in ('$RECYCLE.BIN', 'Recovery', 'System Volume Information'): # 过滤掉无需访问的目录
313
+ return False
314
+ else:
315
+ return os.path.isdir(os.path.join(self.name, f))
316
+
317
+ def FilesRename(self, origin, target, *, 目标目录=None):
318
+ """使用正则规则匹配文件名,并重命名"""
319
+ files = self.Files(正则筛选=origin)
320
+ if not 目标目录: # 如果没有设置目标目录,则以该类所在目录为准
321
+ 目标目录 = self.name
322
+ for fn in files:
323
+ f = File(os.path.join(self.name, fn))
324
+ 目标名称 = re.sub(origin, target, fn, flags=re.IGNORECASE)
325
+ f.rename(os.path.join(目标目录, 目标名称))
326
+
327
+ def 递归输出文件列表(self, *, 当前层级=0, 控制宽度=None):
328
+ """占秋意见:可以根据扩展名简化输出内容"""
329
+ fileString = ', '.join(self.files)
330
+ if isinstance(控制宽度, int):
331
+ fileString = textwrap.shorten(fileString, 控制宽度, placeholder='...')
332
+ s = '{}【{}】({}): {}'.format('\t' * 当前层级, self.path.stem, len(self.files), fileString)
333
+ print(s)
334
+ for folder in self.Folders():
335
+ try: # 有些系统目录会读取不了
336
+ fd = CBaseFolder(pathjoin(self.name, folder))
337
+ fd.递归输出文件列表(当前层级=当前层级 + 1, 控制宽度=控制宽度)
338
+ except:
339
+ continue
340
+
341
+ def 大小(self):
342
+ return File(self.name).size
343
+
344
+ def 删除(self):
345
+ shutil.rmtree(self.name, ignore_errors=True)
346
+
347
+ def __bool__(self):
348
+ return os.path.isdir(str(self.path))
349
+
350
+ def __str__(self):
351
+ return self.name
352
+
353
+
354
+ def 自定义正则规则转为标准正则表达式(s):
355
+ s = s.replace('?', r'[\u4e00-\u9fa5]') # 中文问号匹配任意一个中文字符
356
+ return s
357
+
358
+
359
+ def 文件搜索匹配(源目录, 自定义正则规则, *, 目标类型=('文件', '目录')):
360
+ """ 目标类型=('文件','目录') """
361
+ 匹配文件 = list()
362
+ 源目录前缀长度 = len(源目录)
363
+ 正则规则 = 自定义正则规则转为标准正则表达式(自定义正则规则)
364
+ 所有目录 = tuple(os.walk(源目录))
365
+ for 当前目录名, 包含目录, 包含文件 in 所有目录:
366
+ parts = File(当前目录名).parts
367
+ if '.git' in parts or '$RECYCLE.BIN' in parts: # 去掉'.git'这个备份目录,'$RECYCLE.BIN'这个不知啥鬼目录
368
+ continue
369
+ 相对目录 = 当前目录名[源目录前缀长度 + 1:]
370
+ if '目录' in 目标类型:
371
+ if re.search(正则规则, 相对目录):
372
+ 匹配文件.append(相对目录)
373
+ if '文件' in 目标类型:
374
+ for 文件 in 包含文件:
375
+ 相对路径 = os.path.join(相对目录, 文件)
376
+ if re.search(正则规则, 相对路径):
377
+ 匹配文件.append(相对路径)
378
+ return natural_sort(匹配文件)
379
+
380
+
381
+ def 文件复制(源目录, 自定义正则规则, 目标目录, 新正则名称, *, 目标类型=('文件',)):
382
+ """ 目标类型=('文件','目录') """
383
+ 匹配文件 = 文件搜索匹配(源目录, 自定义正则规则, 目标类型=目标类型)
384
+ # 获得匹配文件后,需要从后往前改,否则产生连锁反应会索引不到
385
+
386
+
387
+ def 文件重命名(源目录, 自定义正则规则, 新正则名称, *, 目标类型=('文件',), 目标目录=None, 调试=True, 输出=True, 覆盖操作=False):
388
+ """因为这个操作风险非常大,所以默认情况下是调试模式,必须手动指定进入非调试模式才会进行实际工作
389
+
390
+ 使用示例:文件重命名(r'D:\2017LaTeX\B暑假教材\高数\高一教师版 - 测试\figs - 副本',
391
+ r'^(.*?)-eps-converted-to[.]png', r'\1.png', 调试=False)
392
+ """
393
+ ls = list()
394
+ 匹配文件 = 文件搜索匹配(源目录, 自定义正则规则, 目标类型=目标类型)
395
+ 正则规则 = 自定义正则规则转为标准正则表达式(自定义正则规则)
396
+ if not 目标目录:
397
+ 目标目录 = 源目录
398
+ for f in reversed(匹配文件):
399
+ f2 = re.sub(正则规则, 新正则名称, f)
400
+ ls.append([f, f2])
401
+ if not 调试:
402
+ targetName = os.path.join(目标目录, f2)
403
+ f3 = File(targetName)
404
+ if f3:
405
+ print('文件已存在:', f3.name)
406
+ if 覆盖操作:
407
+ f3.delete()
408
+ os.rename(os.path.join(源目录, f), targetName)
409
+ else:
410
+ os.rename(os.path.join(源目录, f), targetName)
411
+
412
+ df = pd.DataFrame.from_records(ls, columns=('原文件名', '目标文件名'))
413
+ if 输出:
414
+ PrintFullTable(df)
415
+ return df
416
+
417
+
418
+ # def 目录下查找文本(目录, 文件名筛选, 目标文本):
419
+ # ls = 文件搜索匹配(目录, 文件名筛选, 目标类型=('文件',))
420
+ # ls = list(filter(lambda x: Path(x).backup_time == '', ls)) # 去除备份文件
421
+ # ls = natural_sort(ls)
422
+ # 文件名 = list()
423
+ # 出现次数 = list()
424
+ # 行号 = list()
425
+ # for i, fileName in enumerate(ls):
426
+ # cl = ContentLine(pathjoin(目录, fileName))
427
+ # lines = cl.regular_search(目标文本)
428
+ # if lines:
429
+ # 文件名.append(fileName)
430
+ # 出现次数.append(len(lines))
431
+ # 行号.append(str(lines))
432
+ #
433
+ # pf = pd.DataFrame({'文件名': 文件名, '出现次数': 出现次数, '行号': 行号}, columns=['文件名', '出现次数', '行号'])
434
+ # pf.sort_values(by=['出现次数'], ascending=False, inplace=True)
435
+ # PrintFullTable(pf, 最后一列左对齐=True)
436
+ # return pf
437
+
438
+
439
+ def 目录下查找文本(目录, 文件名筛选, 目标文本, *, 模式='表格'):
440
+ """
441
+ 表格模式:统计每个文件中出现的总次数
442
+ 行文本模式:显示所有匹配的行文本
443
+ """
444
+ ls = 文件搜索匹配(目录, 文件名筛选, 目标类型=('文件',))
445
+ ls = list(filter(lambda x: File(x).backup_time == '', ls)) # 去除备份文件
446
+ ls = natural_sort(ls)
447
+ if 模式 == '表格':
448
+ table = list()
449
+ for i, fileName in enumerate(ls):
450
+ cl = ContentLine(pathjoin(目录, fileName))
451
+ lines = cl.regular_search(目标文本)
452
+ if lines:
453
+ table.append((fileName, len(lines), refine_digits_set(lines)))
454
+
455
+ pf = pd.DataFrame.from_records(table, columns=('文件名', '出现次数', '行号'))
456
+ for i in range(len(pf)):
457
+ pf['出现次数'][i] = int(pf['出现次数'][i])
458
+ pf.sort_values(by=['出现次数'], ascending=False, inplace=True)
459
+ PrintFullTable(pf, 最后一列左对齐=True)
460
+ return pf
461
+ elif 模式 == '行文本':
462
+ for i, fileName in enumerate(ls):
463
+ cl = ContentLine(pathjoin(目录, fileName))
464
+ lines = cl.regular_search(目标文本)
465
+ if lines:
466
+ print()
467
+ # print(fileName) # 不输出根目录版本
468
+ print(pathjoin(目录, fileName)) # 输出根目录版本
469
+ print(cl.lines_content(lines))
470
+ else:
471
+ raise TypeError
472
+
473
+
474
+ def 目录下统计单词出现频数(目录, 文件名筛选, 目标文本=r'(\\?[a-zA-Z]+)(?![a-zA-Z])'):
475
+ """默认会找所有单词,以及tex命令"""
476
+ ls = 文件搜索匹配(目录, 文件名筛选, 目标类型=('文件',))
477
+ s = list()
478
+ for fileName in [f for f in ls if not File(f).backup_time]: # 去除备份文件
479
+ c = File(pathjoin(目录, fileName)).read()
480
+ s.append(c)
481
+ s = '\n'.join(s)
482
+
483
+ # ls = re.findall(r'(?<=\\)([a-zA-Z]+)(?![a-zA-Z])', s) # 统计tex命令数量
484
+ # ls = re.findall(r'([a-zA-Z]+)(?![a-zA-Z])', s) # 统计单词次数
485
+ # ls = re.findall(r'(\\?[a-zA-Z]+)(?![a-zA-Z])', s) # tex和普通单词综合性搜索
486
+ ls = re.findall(目标文本, s)
487
+ d = OrderedDict(sorted(Counter(ls).items(), key=lambda t: -t[1]))
488
+ pf = pd.DataFrame({'关键字': list(d.keys()), '出现次数': list(d.values())}, columns=['关键字', '出现次数'])
489
+ PrintFullTable(pf)
490
+ return pf
491
+
492
+
493
+ def GetFullPathClass(s):
494
+ """如果输入的是相对路径,会解析为绝对路径"""
495
+ # p = Path(s).resolve() # 奕本的电脑这句话运行不了
496
+ p = File(s)
497
+ if not s.startswith('\\') and not p.drive:
498
+ p = File.cwd() / p
499
+ return p
500
+
501
+
502
+ ____other = """"""
503
+
504
+ mydecrypt = base64.b64decode
505
+
506
+
507
+ class LengthFormatter:
508
+ """ 长度换算类,可以在允许浮点小误差的场景使用
509
+ TODO 需要精确运算也是可以的,那就要用分数类来存储底层值了
510
+
511
+ # 默认标准长度是mm,所以初始化一个233数字,就等于用233mm初始化
512
+ >>> LengthFormatter(233).cm # 然后可以转化为cm,计算厘米单位下的长度值
513
+ 23.3
514
+ >>> LengthFormatter('233pt') # 可以用带单位的字符串
515
+ 81.78mm
516
+ >>> LengthFormatter('233.45 pt') # 支持小数、有空格等格式
517
+ 81.94mm
518
+
519
+ 应用举例:把长度超过12cm的hspace都限制在12cm以内
520
+ >> s = NestEnv(s).latexcmd1('hspace').bracket('{', inner=True).\
521
+ replace(lambda x: '12cm' if LengthFormatter(x).cm > 12 else x)
522
+ """
523
+
524
+ # 所有其他单位长度与参照长度mm之间比例关系
525
+ ratio = {'pt': 0.351, # 点
526
+ 'bp': 0.353, # 大点,≈1pt
527
+ 'dd': 0.376, # 迪多,=1.07pt
528
+ 'pc': 4.218, # 派卡,=12pt
529
+ 'sp': 1 / 65536, # 定标点,65536sp=1pt
530
+ 'cm': 10, # 厘米
531
+ 'cc': 4.513, # 西塞罗
532
+ 'in': 25.4, # 英寸,=72.27pt
533
+ 'em': 18, # 1em≈当前字体中M的宽度,在正文12pt情况下,一般为18pt
534
+ 'ex': 12, # 1ex≈当前字体中x的高度,暂按12pt处理
535
+ }
536
+
537
+ def __init__(self, v=0):
538
+ if isinstance(v, (int, float)):
539
+ self.__dict__['mm'] = v
540
+ elif isinstance(v, str):
541
+ m = re.match(r'(-?\d+(?:\.\d*)?)\s*(' + '|'.join(list(self.ratio.keys()) + ['mm']) + ')$', v)
542
+ if not m: raise ValueError(f'不存在的长度单位类型:{v}')
543
+ self.__dict__['mm'] = 0
544
+ self.__setitem__(m.group(2), float(m.group(1)))
545
+ else:
546
+ raise ValueError(f'不存在的长度单位类型:{v}')
547
+
548
+ def __repr__(self):
549
+ return '{:.2f}mm'.format(self.__dict__['mm'])
550
+
551
+ def __getattr__(self, key):
552
+ if key in self.ratio.keys():
553
+ return self.__dict__['mm'] / self.ratio[key]
554
+ else:
555
+ raise ValueError(f'不存在的长度单位类型:{key}')
556
+
557
+ def __setitem__(self, key, value):
558
+ if key == 'mm':
559
+ self.__dict__['mm'] = value
560
+ elif key in self.ratio.keys():
561
+ self.__dict__['mm'] = value * self.ratio[key]
562
+ else:
563
+ raise ValueError(f'不存在的长度单位类型:{key}')
564
+
565
+
566
+ ____image = """
567
+ 暂时还没空整理的一些图片功能
568
+ """
569
+
570
+
571
+ def 缩放目录下所有png图片(folder, rate=120):
572
+ """rate可以控制缩放比例,正常是100
573
+ 再乘120是不想缩放太多,理论上乘100是正常比例
574
+
575
+ 旧函数名:缩放目录下所有png图片
576
+ """
577
+ fd = Dir(folder)
578
+ for f in fd.select_files('*.png'):
579
+ try:
580
+ im = Image.open(str(f))
581
+ if 'dpi' in im.info:
582
+ if im.info['dpi'][0] in (305, 610): # 这个是magick转换过来的特殊值,不能缩放
583
+ continue # 180920周四,610是为欧龙加的,欧龙双师需要设置-density 240
584
+ # print(files, im.info) # dpi: 600
585
+ # print(查看图片的Exif信息(im))
586
+ s = list(im.size)
587
+ s[0] = int(s[0] / im.info['dpi'][0] * rate)
588
+ s[1] = int(s[1] / im.info['dpi'][1] * rate)
589
+ im = im.resize(s, Image.ANTIALIAS)
590
+ im.save(str(f))
591
+ except:
592
+ print('无法处理图片:', f)
593
+ continue
594
+
595
+
596
+ def 缩放目录下所有png图片2(folder, scale=1.0):
597
+ """rate可以控制缩放比例,正常是100
598
+ 再乘120是不想缩放太多,理论上乘100是正常比例
599
+
600
+ 旧函数名:缩放目录下所有png图片2
601
+ """
602
+ fd = Dir(folder)
603
+ for f in fd.select_files('*.png'):
604
+ im = Image.open(str(f))
605
+ s = list(im.size)
606
+ s[0] = int(s[0] * scale)
607
+ s[1] = int(s[1] * scale)
608
+ im = im.resize(s, Image.ANTIALIAS)
609
+ im.save(str(f))
610
+
611
+
612
+ def 查看目录下png图片信息(folder):
613
+ """
614
+ 旧函数名:查看目录下png图片信息
615
+ """
616
+ fd = Dir(folder)
617
+ ls = list()
618
+ for f in fd.select_files('*.png'):
619
+ im = Image.open(str(f))
620
+ d0, d1 = im.info['dpi'] if 'dpi' in im.info else ('', '')
621
+ # 处理eps格式
622
+ epsFile = f.with_suffix('.eps')
623
+ if epsFile:
624
+ epsSize, epsIm = epsFile.大小(), Image.open(epsFile.name)
625
+ boundingBox = epsIm.info['BoundingBox'].replace(' ', ',') if 'BoundingBox' in epsIm.info else ''
626
+ else:
627
+ epsSize, boundingBox = '', ''
628
+ # 处理pdf格式
629
+ pdfFile = File(f.name[:-4] + '-eps-converted-to.pdf')
630
+ pdfSize = pdfFile.size if pdfFile else ''
631
+ # 存储到列表
632
+ ls.append((f, im.size[0], im.size[1], d0, d1,
633
+ f.size, f.mtime.strftime(' %y%m%d-%H%M%S'),
634
+ epsSize, boundingBox, pdfSize))
635
+ df = pd.DataFrame.from_records(ls,
636
+ columns=('fileName', 'width', 'height', 'dpi_w', 'dpi_h', 'size', 'time', 'epsSize',
637
+ 'boundingBox', 'pdfSize'))
638
+ with pd.option_context('display.max_colwidth', -1, 'display.max_columns', 20,
639
+ 'display.width', 200): # 上下文控制格式
640
+ print(df)
641
+ return df
642
+
643
+
644
+ def make_color_transparent(image, color, thresh2=0):
645
+ """ 将指定颜色转为透明
646
+ https://stackoverflow.com/questions/765736/using-pil-to-make-all-white-pixels-transparent/765829
647
+
648
+ 旧函数名:MakeColorTransparent
649
+ """
650
+ from PIL import ImageMath
651
+
652
+ def distance2(a, b):
653
+ return (a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]) + (a[2] - b[2]) * (a[2] - b[2])
654
+
655
+ image = image.convert("RGBA")
656
+ red, green, blue, alpha = image.split()
657
+ image.putalpha(ImageMath.eval("""convert(((((t - d(c, (r, g, b))) >> 31) + 1) ^ 1) * a, 'L')""",
658
+ t=thresh2, d=distance2, c=color, r=red, g=green, b=blue, a=alpha))
659
+ return image
660
+
661
+
662
+ if __name__ == '__main__':
663
+ print('测试')