w-docx-split 1.0.0
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.
- package/.editorconfig +9 -0
- package/.eslintignore +3 -0
- package/.eslintrc.js +55 -0
- package/.jsdoc +25 -0
- package/LICENSE +21 -0
- package/README.md +28 -0
- package/SECURITY.md +5 -0
- package/babel.config.js +16 -0
- package/dist/w-docx-split.umd.js +7 -0
- package/dist/w-docx-split.umd.js.map +1 -0
- package/docs/WDocxSplit.mjs.html +199 -0
- package/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
- package/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
- package/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
- package/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
- package/docs/global.html +519 -0
- package/docs/index.html +84 -0
- package/docs/scripts/collapse.js +39 -0
- package/docs/scripts/commonNav.js +28 -0
- package/docs/scripts/linenumber.js +25 -0
- package/docs/scripts/nav.js +12 -0
- package/docs/scripts/polyfill.js +4 -0
- package/docs/scripts/prettify/Apache-License-2.0.txt +202 -0
- package/docs/scripts/prettify/lang-css.js +2 -0
- package/docs/scripts/prettify/prettify.js +28 -0
- package/docs/scripts/search.js +99 -0
- package/docs/styles/jsdoc.css +776 -0
- package/docs/styles/prettify.css +80 -0
- package/g.mjs +29 -0
- package/package.json +32 -0
- package/script.txt +17 -0
- package/scripts/install.mjs +30 -0
- package/src/WDocxSplit.mjs +127 -0
- package/src/downloadFiles.mjs +23 -0
- package/srcPython/build.bat +9 -0
- package/srcPython/run.bat +4 -0
- package/srcPython/splitDocx.py +271 -0
- package/srcPython/splitDocx.spec +37 -0
- package/srcPython//350/252/252/346/230/216.txt +24 -0
- package/test/WDocxSplit.test.mjs +40 -0
- package/test/docin.docx +0 -0
- package/test/outTrue/001.docx +0 -0
- package/test/outTrue/002.docx +0 -0
- package/toolg/addVersion.mjs +4 -0
- package/toolg/cleanFolder.mjs +4 -0
- package/toolg/gDistRollup.mjs +28 -0
- package/toolg/modifyReadme.mjs +4 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
.pln {
|
|
2
|
+
color: #ddd;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
/* string content */
|
|
6
|
+
.str {
|
|
7
|
+
color: #61ce3c;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/* a keyword */
|
|
11
|
+
.kwd {
|
|
12
|
+
color: #fbde2d;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* a comment */
|
|
16
|
+
.com {
|
|
17
|
+
color: #aeaeae;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/* a type name */
|
|
21
|
+
.typ {
|
|
22
|
+
color: #8da6ce;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* a literal value */
|
|
26
|
+
.lit {
|
|
27
|
+
color: #fbde2d;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* punctuation */
|
|
31
|
+
.pun {
|
|
32
|
+
color: #ddd;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* lisp open bracket */
|
|
36
|
+
.opn {
|
|
37
|
+
color: #000000;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* lisp close bracket */
|
|
41
|
+
.clo {
|
|
42
|
+
color: #000000;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* a markup tag name */
|
|
46
|
+
.tag {
|
|
47
|
+
color: #8da6ce;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* a markup attribute name */
|
|
51
|
+
.atn {
|
|
52
|
+
color: #fbde2d;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* a markup attribute value */
|
|
56
|
+
.atv {
|
|
57
|
+
color: #ddd;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/* a declaration */
|
|
61
|
+
.dec {
|
|
62
|
+
color: #EF5050;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* a variable name */
|
|
66
|
+
.var {
|
|
67
|
+
color: #c82829;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* a function name */
|
|
71
|
+
.fun {
|
|
72
|
+
color: #4271ae;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* Specify class=linenums on a pre to get line numbering */
|
|
76
|
+
ol.linenums {
|
|
77
|
+
margin-top: 0;
|
|
78
|
+
margin-bottom: 0;
|
|
79
|
+
padding-bottom: 2px;
|
|
80
|
+
}
|
package/g.mjs
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import w from 'wsemi'
|
|
2
|
+
import WDocxSplit from './src/WDocxSplit.mjs'
|
|
3
|
+
//import WDocxSplit from 'w-docx-split/src/WDocxSplit.mjs'
|
|
4
|
+
//import WDocxSplit from 'w-docx-split'
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
async function test() {
|
|
8
|
+
|
|
9
|
+
let fpIn = `./test/docin.docx`
|
|
10
|
+
let strSep = '[systag:sepline]'
|
|
11
|
+
let fdOut = `./test/out`
|
|
12
|
+
let opt = {
|
|
13
|
+
padZero: 3,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let r = await WDocxSplit(fpIn, strSep, fdOut, opt)
|
|
17
|
+
console.log(r)
|
|
18
|
+
// => ok
|
|
19
|
+
|
|
20
|
+
w.fsDeleteFolder(fdOut)
|
|
21
|
+
|
|
22
|
+
}
|
|
23
|
+
test()
|
|
24
|
+
.catch((err) => {
|
|
25
|
+
console.log('catch', err)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
//node g.mjs
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "w-docx-split",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "dist/w-docx-split.umd.js",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"lodash-es": "^4.17.22",
|
|
7
|
+
"wsemi": "^1.8.38"
|
|
8
|
+
},
|
|
9
|
+
"devDependencies": {
|
|
10
|
+
"w-package-tools": "^1.1.2"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"postinstall": "node scripts/install.mjs",
|
|
14
|
+
"test": "mocha --parallel --timeout 60000",
|
|
15
|
+
"deploy": "gh-pages -d docs"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/yuda-lyu/w-docx-split.git"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"package",
|
|
23
|
+
"tool",
|
|
24
|
+
"win32com",
|
|
25
|
+
"html",
|
|
26
|
+
"docx",
|
|
27
|
+
"windows",
|
|
28
|
+
"nodejs"
|
|
29
|
+
],
|
|
30
|
+
"author": "yuda-lyu(semisphere)",
|
|
31
|
+
"license": "MIT"
|
|
32
|
+
}
|
package/script.txt
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#node toolg/addVersion.mjs
|
|
2
|
+
node toolg/modifyReadme.mjs
|
|
3
|
+
|
|
4
|
+
node toolg/cleanFolder.mjs
|
|
5
|
+
./node_modules/.bin/jsdoc -c .jsdoc
|
|
6
|
+
|
|
7
|
+
node toolg/gDistRollup.mjs
|
|
8
|
+
|
|
9
|
+
git add . -A
|
|
10
|
+
git commit -m 'modify: '
|
|
11
|
+
git push origin master:master
|
|
12
|
+
|
|
13
|
+
npm run deploy
|
|
14
|
+
|
|
15
|
+
#npm test
|
|
16
|
+
|
|
17
|
+
#npm publish
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import { fileURLToPath } from 'url'
|
|
3
|
+
import downloadFiles from '../src/downloadFiles.mjs'
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
async function init() {
|
|
7
|
+
|
|
8
|
+
//check, 被安裝條件才執行
|
|
9
|
+
let __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
10
|
+
if (!__dirname.includes('node_modules')) {
|
|
11
|
+
return //非位於node_modules, 代表套件本身
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
//fdSrv
|
|
15
|
+
let fdSrv = path.resolve()
|
|
16
|
+
|
|
17
|
+
//fdBase,
|
|
18
|
+
let fdBase = `${fdSrv}/src/` //npm i後觸發安裝時, 工作路徑是位於套件內
|
|
19
|
+
// console.log('fdBase', fdBase)
|
|
20
|
+
|
|
21
|
+
//downloadFiles
|
|
22
|
+
await downloadFiles(fdBase)
|
|
23
|
+
|
|
24
|
+
}
|
|
25
|
+
init()
|
|
26
|
+
.catch((err) => {
|
|
27
|
+
console.log(err)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
//node scripts/install.mjs
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import process from 'process'
|
|
3
|
+
import get from 'lodash-es/get.js'
|
|
4
|
+
import isestr from 'wsemi/src/isestr.mjs'
|
|
5
|
+
import isp0int from 'wsemi/src/isp0int.mjs'
|
|
6
|
+
import str2b64 from 'wsemi/src/str2b64.mjs'
|
|
7
|
+
import execProcess from 'wsemi/src/execProcess.mjs'
|
|
8
|
+
import fsIsFile from 'wsemi/src/fsIsFile.mjs'
|
|
9
|
+
import fsIsFolder from 'wsemi/src/fsIsFolder.mjs'
|
|
10
|
+
import fsCreateFolder from 'wsemi/src/fsCreateFolder.mjs'
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
let fdSrv = path.resolve()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
function isWindows() {
|
|
17
|
+
return process.platform === 'win32'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 依照指定字串分割Docx檔
|
|
23
|
+
*
|
|
24
|
+
* @param {String} fpIn 輸入來源Html檔位置字串
|
|
25
|
+
* @param {String} strSep 輸入內文會提供之分割字串
|
|
26
|
+
* @param {String} fdOut 輸入轉出Docx檔位置字串
|
|
27
|
+
* @param {Object} [opt={}] 輸入設定物件,預設{}
|
|
28
|
+
* @param {Integer} [opt.padZero=0] 輸入是否補0位數整數,例如padZero=3時檔名會變成001.docx,預設0
|
|
29
|
+
* @returns {Promise} 回傳Promise,resolve回傳成功訊息,reject回傳錯誤訊息
|
|
30
|
+
* @example
|
|
31
|
+
*
|
|
32
|
+
|
|
33
|
+
*
|
|
34
|
+
*/
|
|
35
|
+
async function WDocxSplit(fpIn, strSep, fdOut, opt = {}) {
|
|
36
|
+
let errTemp = null
|
|
37
|
+
|
|
38
|
+
//isWindows
|
|
39
|
+
if (!isWindows()) {
|
|
40
|
+
return Promise.reject('operating system is not windows')
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
//check
|
|
44
|
+
if (!fsIsFile(fpIn)) {
|
|
45
|
+
return Promise.reject(`fpIn[${fpIn}] does not exist`)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
//check
|
|
49
|
+
if (!isestr(strSep)) {
|
|
50
|
+
return Promise.reject(`strSep[${strSep}] is not an effective string`)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
//check
|
|
54
|
+
if (!fsIsFolder(fdOut)) {
|
|
55
|
+
fsCreateFolder(fdOut)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
//padZero
|
|
59
|
+
let padZero = get(opt, 'padZero')
|
|
60
|
+
if (!isp0int(padZero)) {
|
|
61
|
+
padZero = 0
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
//轉絕對路徑
|
|
65
|
+
fpIn = path.resolve(fpIn)
|
|
66
|
+
fdOut = path.resolve(fdOut)
|
|
67
|
+
|
|
68
|
+
//fnExe
|
|
69
|
+
let fnExe = `splitDocx.exe`
|
|
70
|
+
|
|
71
|
+
//fdExe
|
|
72
|
+
let fdExe = ''
|
|
73
|
+
if (true) {
|
|
74
|
+
let fdExeSrc = `${fdSrv}/src/`
|
|
75
|
+
let fdExeNM = `${fdSrv}/node_modules/w-docx-split/src/`
|
|
76
|
+
if (fsIsFile(`${fdExeSrc}${fnExe}`)) {
|
|
77
|
+
fdExe = fdExeSrc
|
|
78
|
+
}
|
|
79
|
+
else if (fsIsFile(`${fdExeNM}${fnExe}`)) {
|
|
80
|
+
fdExe = fdExeNM
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
return Promise.reject('can not find folder for html2docx')
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// console.log('fdExe', fdExe)
|
|
87
|
+
|
|
88
|
+
//prog
|
|
89
|
+
let prog = `${fdExe}${fnExe}`
|
|
90
|
+
// console.log('prog', prog)
|
|
91
|
+
|
|
92
|
+
//inp
|
|
93
|
+
let inp = {
|
|
94
|
+
fpIn,
|
|
95
|
+
strSep,
|
|
96
|
+
fdOut,
|
|
97
|
+
padZero,
|
|
98
|
+
}
|
|
99
|
+
// console.log('inp', inp)
|
|
100
|
+
|
|
101
|
+
//input to b64
|
|
102
|
+
let cInput = JSON.stringify(inp)
|
|
103
|
+
let b64Input = str2b64(cInput)
|
|
104
|
+
// console.log('b64Input', b64Input)
|
|
105
|
+
|
|
106
|
+
//execProcess
|
|
107
|
+
await execProcess(prog, b64Input)
|
|
108
|
+
.catch((err) => {
|
|
109
|
+
console.log('execProcess catch', err)
|
|
110
|
+
errTemp = err.toString()
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
//check
|
|
114
|
+
if (errTemp) {
|
|
115
|
+
return Promise.reject(errTemp)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// //check
|
|
119
|
+
// if (!isestr(output)) {
|
|
120
|
+
// return Promise.reject(`output[${cstr(output)}] is not an effective string`)
|
|
121
|
+
// }
|
|
122
|
+
|
|
123
|
+
return 'ok'
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
export default WDocxSplit
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import fsDownloadFile from 'wsemi/src/fsDownloadFile.mjs'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
async function downloadFiles(fdBase) {
|
|
5
|
+
|
|
6
|
+
//url
|
|
7
|
+
let url = `https://github.com/yuda-lyu/w-docx-split/raw/refs/heads/master/src/splitDocx.exe`
|
|
8
|
+
// console.log('url',url)
|
|
9
|
+
|
|
10
|
+
//fn
|
|
11
|
+
let fn = `splitDocx.exe`
|
|
12
|
+
|
|
13
|
+
//fp
|
|
14
|
+
let fp = `${fdBase}${fn}`
|
|
15
|
+
|
|
16
|
+
//fsDownloadFile
|
|
17
|
+
console.log(`downloading url[${url}]...`, `to fp[${fp}]`)
|
|
18
|
+
await fsDownloadFile(url, fp)
|
|
19
|
+
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
export default downloadFiles
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
from win32com import client as wc
|
|
2
|
+
|
|
3
|
+
#使用win32com
|
|
4
|
+
#win32com因更新問題會出現 ImportError: DLL load failed while importing win32api: 找不到指定的模組。
|
|
5
|
+
#1. 安裝 pip install pywin32
|
|
6
|
+
#2. 使用系統管理員權限開啟cmd
|
|
7
|
+
#3. cd至安裝目錄 C:\ProgramData\Anaconda3\Scripts
|
|
8
|
+
#4. 用python安裝腳本 python pywin32_postinstall.py -install
|
|
9
|
+
|
|
10
|
+
#編譯
|
|
11
|
+
#1. 安裝編譯套件 pip install pyinstaller
|
|
12
|
+
#2. 編譯 pyinstaller -F splitDocx.py
|
|
13
|
+
|
|
14
|
+
#win32com教學
|
|
15
|
+
#https://zhuanlan.zhihu.com/p/67543981
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def getError():
|
|
19
|
+
import sys
|
|
20
|
+
|
|
21
|
+
#exc_info
|
|
22
|
+
type, message, traceback = sys.exc_info()
|
|
23
|
+
|
|
24
|
+
#es
|
|
25
|
+
es=[]
|
|
26
|
+
while traceback:
|
|
27
|
+
e={
|
|
28
|
+
'name':traceback.tb_frame.f_code.co_name,
|
|
29
|
+
'filename':traceback.tb_frame.f_code.co_filename,
|
|
30
|
+
}
|
|
31
|
+
es.append(e)
|
|
32
|
+
traceback = traceback.tb_next
|
|
33
|
+
|
|
34
|
+
#err
|
|
35
|
+
err={
|
|
36
|
+
'type':type,
|
|
37
|
+
'message':message,
|
|
38
|
+
'traceback':es,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return err
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def j2o(v):
|
|
45
|
+
#json轉物件
|
|
46
|
+
import json
|
|
47
|
+
return json.loads(v)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def o2j(v):
|
|
51
|
+
#物件轉json
|
|
52
|
+
import json
|
|
53
|
+
return json.dumps(v, ensure_ascii=False)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def str2b64(v):
|
|
57
|
+
#字串轉base64字串
|
|
58
|
+
import base64
|
|
59
|
+
v=base64.b64encode(v.encode('utf-8'))
|
|
60
|
+
return str(v,'utf-8')
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def b642str(v):
|
|
64
|
+
#base64字串轉字串
|
|
65
|
+
import base64
|
|
66
|
+
return base64.b64decode(v)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def readText(fn):
|
|
70
|
+
#讀取檔案fn內文字
|
|
71
|
+
import codecs
|
|
72
|
+
with codecs.open(fn,'r',encoding='utf8') as f:
|
|
73
|
+
return f.read()
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def writeText(fn,str):
|
|
77
|
+
#寫出文字str至檔案fn
|
|
78
|
+
import codecs
|
|
79
|
+
with codecs.open(fn,'w',encoding='utf8') as f:
|
|
80
|
+
f.write(str)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def splitDocx(fpIn, strSep, fdOut, opt):
|
|
84
|
+
|
|
85
|
+
#Dispatch
|
|
86
|
+
app = wc.Dispatch('Word.Application')
|
|
87
|
+
|
|
88
|
+
#正式版須隱藏
|
|
89
|
+
app.Visible = False
|
|
90
|
+
|
|
91
|
+
#不詢問使用者
|
|
92
|
+
app.DisplayAlerts = False
|
|
93
|
+
|
|
94
|
+
docIn = None
|
|
95
|
+
try:
|
|
96
|
+
|
|
97
|
+
# Open
|
|
98
|
+
docIn = app.Documents.Open(fpIn)
|
|
99
|
+
|
|
100
|
+
# 逐段落掃描
|
|
101
|
+
# Word 的 Paragraphs 索引是 1-based
|
|
102
|
+
# 先掃一次切成多組 paragraph index 區間
|
|
103
|
+
groups = []
|
|
104
|
+
cur = []
|
|
105
|
+
i = 0
|
|
106
|
+
for p in docIn.Paragraphs:
|
|
107
|
+
i += 1
|
|
108
|
+
t = p.Range.Text or ""
|
|
109
|
+
|
|
110
|
+
# 判斷是否為分隔段
|
|
111
|
+
is_sep = (strSep in t)
|
|
112
|
+
|
|
113
|
+
if is_sep:
|
|
114
|
+
if len(cur) > 0:
|
|
115
|
+
groups.append(cur)
|
|
116
|
+
cur = []
|
|
117
|
+
else:
|
|
118
|
+
cur.append(i)
|
|
119
|
+
|
|
120
|
+
if len(cur) > 0:
|
|
121
|
+
groups.append(cur)
|
|
122
|
+
|
|
123
|
+
# 沒任何內容也要合理處理
|
|
124
|
+
# groups 可能為 [],代表整份文件都是分隔符或空
|
|
125
|
+
total = len(groups)
|
|
126
|
+
|
|
127
|
+
# 逐組輸出
|
|
128
|
+
padZero = opt.get('padZero', None)
|
|
129
|
+
|
|
130
|
+
for idx, paraIdxList in enumerate(groups, start=1):
|
|
131
|
+
|
|
132
|
+
# 檔名:1.docx ~ n.docx
|
|
133
|
+
if isinstance(padZero, int) and padZero > 0:
|
|
134
|
+
fn = str(idx).zfill(padZero) + '.docx'
|
|
135
|
+
else:
|
|
136
|
+
fn = str(idx) + '.docx'
|
|
137
|
+
|
|
138
|
+
# 若 fdOut 結尾已有\會變成\\, 得使用rstrip處理
|
|
139
|
+
fpOut = fdOut.rstrip('\\/') + '\\' + fn
|
|
140
|
+
|
|
141
|
+
# Add new document
|
|
142
|
+
docOut = app.Documents.Add()
|
|
143
|
+
|
|
144
|
+
try:
|
|
145
|
+
# 逐段落拷貝格式化內容(不走剪貼簿)
|
|
146
|
+
# 用 rngOut 的結尾做 append
|
|
147
|
+
rngOut = docOut.Content
|
|
148
|
+
WdCollapseEnd = 0 # wdCollapseEnd
|
|
149
|
+
for pi in paraIdxList:
|
|
150
|
+
rngSrc = docIn.Paragraphs(pi).Range
|
|
151
|
+
rngOut.Collapse(WdCollapseEnd)
|
|
152
|
+
|
|
153
|
+
# 這句是關鍵:不經剪貼簿,直接拷貝格式化文字
|
|
154
|
+
rngOut.FormattedText = rngSrc.FormattedText
|
|
155
|
+
|
|
156
|
+
# SaveAs2
|
|
157
|
+
WdSaveFormat = 16 # wdFormatDocumentDefault=16 (.docx)
|
|
158
|
+
docOut.SaveAs2(fpOut, WdSaveFormat)
|
|
159
|
+
|
|
160
|
+
finally:
|
|
161
|
+
# Close output doc
|
|
162
|
+
try:
|
|
163
|
+
WdDoNotSaveChanges = 0 # wdDoNotSaveChanges
|
|
164
|
+
docOut.Close(WdDoNotSaveChanges)
|
|
165
|
+
except:
|
|
166
|
+
pass
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
'total': total,
|
|
170
|
+
'fdOut': fdOut,
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
finally:
|
|
174
|
+
# Close input doc & quit word
|
|
175
|
+
try:
|
|
176
|
+
if docIn is not None:
|
|
177
|
+
WdDoNotSaveChanges = 0
|
|
178
|
+
docIn.Close(WdDoNotSaveChanges)
|
|
179
|
+
except:
|
|
180
|
+
pass
|
|
181
|
+
|
|
182
|
+
try:
|
|
183
|
+
WdSaveOptions = 0 # wdDoNotSaveChanges
|
|
184
|
+
app.Quit(WdSaveOptions)
|
|
185
|
+
except:
|
|
186
|
+
pass
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def core(b64):
|
|
190
|
+
state=''
|
|
191
|
+
|
|
192
|
+
try:
|
|
193
|
+
|
|
194
|
+
#b642str
|
|
195
|
+
s=b642str(b64)
|
|
196
|
+
|
|
197
|
+
#j2o
|
|
198
|
+
o=j2o(s)
|
|
199
|
+
|
|
200
|
+
#params
|
|
201
|
+
fpIn=o['fpIn']
|
|
202
|
+
strSep=o['strSep']
|
|
203
|
+
fdOut=o['fdOut']
|
|
204
|
+
|
|
205
|
+
#opt
|
|
206
|
+
opt={}
|
|
207
|
+
opt['padZero']=o['padZero']
|
|
208
|
+
|
|
209
|
+
#splitDocx
|
|
210
|
+
splitDocx(fpIn, strSep, fdOut, opt)
|
|
211
|
+
|
|
212
|
+
state='success'
|
|
213
|
+
except:
|
|
214
|
+
err=getError()
|
|
215
|
+
state='error: '+str(err["message"])
|
|
216
|
+
|
|
217
|
+
return state
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def run():
|
|
221
|
+
import sys
|
|
222
|
+
|
|
223
|
+
#由外部程序呼叫或直接給予檔案路徑
|
|
224
|
+
state=''
|
|
225
|
+
argv=sys.argv
|
|
226
|
+
#argv=['','']
|
|
227
|
+
if len(argv)==2:
|
|
228
|
+
|
|
229
|
+
#b64
|
|
230
|
+
b64=sys.argv[1]
|
|
231
|
+
|
|
232
|
+
#core
|
|
233
|
+
state=core(b64)
|
|
234
|
+
|
|
235
|
+
else:
|
|
236
|
+
#print(sys.argv)
|
|
237
|
+
state='error: invalid length of argv'
|
|
238
|
+
|
|
239
|
+
#print & flush
|
|
240
|
+
print(state)
|
|
241
|
+
sys.stdout.flush()
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
if True:
|
|
245
|
+
#正式版
|
|
246
|
+
|
|
247
|
+
#run
|
|
248
|
+
run()
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
if False:
|
|
252
|
+
#產生測試輸入b64
|
|
253
|
+
|
|
254
|
+
#inp
|
|
255
|
+
inp={
|
|
256
|
+
'fpIn':'D:\\- 006 - 開源\\開源-JS-008-4-w-docx-split\\w-docx-split\\srcPython\\bbb\\docin.docx',
|
|
257
|
+
'strSep':'[systag:sepline]',
|
|
258
|
+
'fdOut':'D:\\- 006 - 開源\\開源-JS-008-4-w-docx-split\\w-docx-split\\srcPython\\bbb2',
|
|
259
|
+
'padZero': 0,
|
|
260
|
+
}
|
|
261
|
+
# print(o2j(inp))
|
|
262
|
+
|
|
263
|
+
#str2b64
|
|
264
|
+
b64=str2b64(o2j(inp))
|
|
265
|
+
print(b64)
|
|
266
|
+
|
|
267
|
+
#core
|
|
268
|
+
state=core(b64)
|
|
269
|
+
|
|
270
|
+
print(state)
|
|
271
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# -*- mode: python ; coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
a = Analysis(
|
|
5
|
+
['splitDocx.py'],
|
|
6
|
+
pathex=[],
|
|
7
|
+
binaries=[],
|
|
8
|
+
datas=[],
|
|
9
|
+
hiddenimports=[],
|
|
10
|
+
hookspath=[],
|
|
11
|
+
hooksconfig={},
|
|
12
|
+
runtime_hooks=[],
|
|
13
|
+
excludes=[],
|
|
14
|
+
noarchive=False,
|
|
15
|
+
)
|
|
16
|
+
pyz = PYZ(a.pure)
|
|
17
|
+
|
|
18
|
+
exe = EXE(
|
|
19
|
+
pyz,
|
|
20
|
+
a.scripts,
|
|
21
|
+
a.binaries,
|
|
22
|
+
a.datas,
|
|
23
|
+
[],
|
|
24
|
+
name='splitDocx',
|
|
25
|
+
debug=False,
|
|
26
|
+
bootloader_ignore_signals=False,
|
|
27
|
+
strip=False,
|
|
28
|
+
upx=True,
|
|
29
|
+
upx_exclude=[],
|
|
30
|
+
runtime_tmpdir=None,
|
|
31
|
+
console=True,
|
|
32
|
+
disable_windowed_traceback=False,
|
|
33
|
+
argv_emulation=False,
|
|
34
|
+
target_arch=None,
|
|
35
|
+
codesign_identity=None,
|
|
36
|
+
entitlements_file=None,
|
|
37
|
+
)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
0.可用pyinstaller或nuitka編譯,但nuitka編譯出檔案會小一點(4x mb),不過卻無法執行待研究
|
|
3
|
+
|
|
4
|
+
1.可先用一般編譯方式產生spec檔: pyinstaller -F splitDocx.py,就會產生splitDocx.spec
|
|
5
|
+
|
|
6
|
+
2.若有需要修改spec後,編譯指令改為對spec檔編譯: pyinstaller build.spec
|
|
7
|
+
|
|
8
|
+
3.使用build.bat進行編譯
|
|
9
|
+
|
|
10
|
+
8.編譯完複製splitDocx.exe至bin,使用bin\run.bat執行,傳入的b64可將物件
|
|
11
|
+
{
|
|
12
|
+
'fpIn':'input.html',
|
|
13
|
+
'fpOut':'output.docx'
|
|
14
|
+
}
|
|
15
|
+
序列化成字串再轉base64即可
|
|
16
|
+
|
|
17
|
+
----------------------------------------------------------------------
|
|
18
|
+
參考
|
|
19
|
+
|
|
20
|
+
解决方法:pyinstaller打包缺文件
|
|
21
|
+
https://www.geek-share.com/detail/2773482967.html
|
|
22
|
+
|
|
23
|
+
pyinstaller spec文件
|
|
24
|
+
https://pyinstaller.readthedocs.io/en/stable/spec-files.html
|