|
楼主 |
发表于 2024-10-7 06:45
|
显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用 · 内置多项VBA编程加强工具 ★ 免费下载 ★ ★ 使用手册★
感谢 sunya_0529 老师,写了一个 JSA 代码!- function 药方整理() {
- const units = ['克', '枚', '粒', '片', '只', '条', '个', '寸', '毫升', '杯', '剂'].join('|'); //定义药方中用到的计量单位
- const sortMaterials = (str) => { //定义一个函数,对传入的字符串解析后分组排序,并输出新字符串
- let strStart = /^((\d+)|(.+?:)).+/.test(str) ? str.match(/^((\d+)|(.+?:)).+/)[1] : ''; //定义前导字符串
- let materials = str
- .replace(strStart, '') //替换掉前导字符串
- .replace('\r', '') //替换掉换行符
- .replace(/[。、,]$/, '') //替换掉行末的“。、,”
- .replace(new RegExp(`(\\d*\\.?\\d+(${units})(([^()]+))?)(?=[、,。])`, 'g'), '$1;') //识别“*克(*)”并在其后插入“;”
- .split(';'); //以“;”为分隔符,把字符串拆分成各组
- let strEnd = materials[materials.length - 1]; //取分组中的最后一个元素,不包括“*单位”的话,就作为收尾字符串,加到结果字符串的后面
- strEnd = new RegExp(`.*\\d*\\.?\\d+(${units}).*`).test(strEnd) ? '' : strEnd.replace(/^[、,。]|[、,。]$/g, '');
- let arrTemp = []; //定义临时数组,存储整理排序后的药材数据
- if (materials) {
- const obj = materials.reduce((a, c) => { //在各组药材中循环
- let arr = c
- .replace(/^[。、,]/, '') //替换掉行首的“。、,”
- .replace(/(,各)(?=\d*\.?\d+)/g, '|') //将“,各”替换成“|”
- .replace(/(?<=(.+?)、(?=.+?))/g, '※') //将“()”内的“、”替换为“※”
- .replace(/、/g, '|') //将“、”替换为“|”
- .replace(/※/g, '、') //将“()”内的“※”替换为“、”(还原)
- .replace(new RegExp(`((\\d*\\.?\\d+~)?\\d*\\.?\\d+(${units}))`, 'g'), `|$1`) //在“[药材名][数量][单位]”的“[数量]”前插入“|”
- .split('|') //以“|”为分隔符拆分字符串
- .filter(Boolean); //过滤掉空值,将字符串拆分成“[药材名1,药材名2,...,*单位]”的数组
- let unit = String(arr[arr.length - 1])
- .replace(/(.+)/g, '') //替换掉“(*)”
- .replace(new RegExp(`[^${units}]`, 'g'), ''); //获取单位
- let amount = String(arr[arr.length - 1]).split(unit)[0]; //获取数量
- a[unit] ??= {}; //以单位为键
- arr.slice(0, -1).forEach(v => {
- a[unit][amount] ??= []; //以数量为二级对象的键,值为数组,用来储存对应的药材名
- a[unit][amount].push(v + String(arr[arr.length - 1]).split(unit)[1]); //将药材名存入数组,同时“*单位”后的内容加在各药材后
- });
- return a;
- }, {});
- for (let o in obj) { //在obj对象中循环
- Object.keys(obj[o]).sort((a, b) => { //对数量进行降序排序
- return (Number(b) ? b : b.slice(b.lastIndexOf('~') + 1)) - (Number(a) ? a : a.slice(a.lastIndexOf('~') + 1));
- }).forEach(n => { //循环读取药材数组,写入临时数组arrTemp
- let brr = obj[o][n];
- arrTemp.push(brr.length > 1 ? `${brr.join('、')},各${n}${o}` : `${brr[0]}${n}${o}`);
- });
- }
- if (strEnd.length) arrTemp.push(strEnd); //收尾字符串不为''的话,加入临时数组
- }
- return `${strStart}${arrTemp.join(';')}`; //函数返回拼接完整的字符串
- }
- const res = []; //定义结果储存数组
- [...ActiveDocument.Paragraphs].forEach((p, i) => { //在文档中各段落循环
- let strPara = p.Range.Text; //定义段落文本
- if (strPara !== '\r' && !strPara.startsWith('【整理】')) {
- res.push(strPara);
- if (new RegExp(`(\\d*\\.?\\d+(${units}))+`).test(strPara) && !strPara.startsWith('替换为:')) {
- let strSub = strPara.match(new RegExp(`[^、,。)]+([^)]*(\\d*\\.?\\d+(${units}))[^(]*)(?=[、,。]?)`, 'g'));
- if (strSub) strSub = strSub.map(s => { //剔除子配方的字符串
- strPara = strPara.replace(s, '');
- let str1 = s.slice(0, s.indexOf('(') + 1);
- if (!new RegExp(`.+\\d*\\.?\\d+(${units})($`).test(str1)) { //调用函数,对“()”内的内容进行整理
- let str2 = s.slice(s.indexOf('(') + 1, s.indexOf(')'));
- return `${str1}${sortMaterials(str2)})`;
- } else {
- return s;
- }
- });
- res.push(`【整理】——${sortMaterials(strPara)}${strSub ? ';' + strSub.join(';') : ''}。\r`)
- }
- }
- });
- ActiveDocument.Content.Delete(); //清空文档内容
- res.forEach(t => {
- let myRange = ActiveDocument.Paragraphs.Last.Range
- myRange.Text = t + '\r';
- if (t.startsWith('【整理】')) myRange.Font.ColorIndex = 5;
- });
- }
复制代码
|
|