dsh-math-calculator 2.3.3 → 2.3.5
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/CHANGELOG.md +180 -0
- package/dsh.plugin.json +1 -1
- package/lib/formula-library-process.js +375 -0
- package/lib/formulas.js +4 -0
- package/lib/guards.js +30 -2
- package/lib/help.js +513 -156
- package/lib/index.js +57 -11
- package/lib/types/formula-library-process.d.ts +45 -0
- package/lib/types/help.d.ts +15 -1
- package/package.json +1 -1
- package/src/formula-library-process.ts +393 -0
- package/src/formulas.ts +3 -0
- package/src/guards.ts +28 -1
- package/src/help.ts +527 -158
- package/src/index.ts +57 -9
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,186 @@
|
|
|
2
2
|
|
|
3
3
|
本项目遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/) 与 [语义化版本](https://semver.org/lang/zh-CN/)。
|
|
4
4
|
|
|
5
|
+
## [2.3.5] — 2026-11-08
|
|
6
|
+
|
|
7
|
+
针对《极限工程》项目的两份实测反馈。逐条核实后**多数条目已在之前版本修好**;
|
|
8
|
+
本批只做两处真缺陷 + 补工艺公式。
|
|
9
|
+
|
|
10
|
+
### 修复(precision 调低后结果被截成 0,却 ok=true + notice 空)
|
|
11
|
+
|
|
12
|
+
反馈原话:「precision=20 时结果静默变成 0,`ok` 依然是 `true`,`notice` 为空」。
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
(10^20+1)-(10^20), precision=20 → 0 ok=true, notice 空
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
根因不是「没检查」,而是**检查只看了输出**:结果被截成 0 后只有 1 位,
|
|
19
|
+
判据「整数位数 > precision」立刻放行 —— **越离谱的结果越容易逃过检查**。
|
|
20
|
+
|
|
21
|
+
修法:改成**看输入而不只看输出**。表达式里出现 `10^n`(n ≥ precision)或长整数串时,
|
|
22
|
+
无论结果多小都提示:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
notice: 表达式里出现了超出 precision=20 能表示的大数,
|
|
26
|
+
结果可能已失真(本次结果 0)。需要精确值请用 precision:64…
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
临界点是 `>=` 不是 `>`:`10^20` 是「1 后跟 20 个零」= **21 位**,precision=20 装不下它。
|
|
30
|
+
第一版写成 `>`,恰好漏掉了这个案例。
|
|
31
|
+
|
|
32
|
+
### 修复(label 括号内的「输入条件」被当成「结果单位」)
|
|
33
|
+
|
|
34
|
+
反馈原话:label「煤储量/年耗 可支撑年数(2万吨)」被警告「若按字面读成万则为 1.47e8」,
|
|
35
|
+
而作者真实意思是「**2 万吨煤**能支撑多少年」—— 括号里是输入口径,不是结果单位。
|
|
36
|
+
|
|
37
|
+
判据:括号内含「数字 + 量级词 + 单位词」(`2万吨`、`300万件`)→ 判为输入条件,放过;
|
|
38
|
+
括号内只有「量级词 + 单位词」(`亿`、`万吨`)→ 仍按结果单位处理。
|
|
39
|
+
|
|
40
|
+
反向对照守住了:`年发电量(亿)` 仍正常报警,`1亿棵树日产台`、`年耗H2O万吨` 仍不误报。
|
|
41
|
+
|
|
42
|
+
### 新增(工艺级工程公式 14 条,公式库 499 → 513)
|
|
43
|
+
|
|
44
|
+
反馈的核心判断(实测证实):
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
physics 187 条 ← 极充实,解释「世界为什么这样」
|
|
48
|
+
engineering 21 条 ← 全是顶层物理式(梁柱/热机/管流/泵)
|
|
49
|
+
机械 0 命中 | 发酵 0 命中 | 窑 0 命中
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
> 「已有的 187 条物理规律往下接一层就够用,**缺的是那座桥**。」
|
|
53
|
+
|
|
54
|
+
| 链 | 公式 | 关键性质 |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| 能源 | `kiln_heat_balance` | 反馈点名的「全库第一缺口」:有了它「单窑耗煤 8kg」才能验算 |
|
|
57
|
+
| 能源 | `kiln_firing_time` | 升温速率被热应力卡住,壁厚翻倍工期翻倍 |
|
|
58
|
+
| 能源 | `wall_heat_loss` | 用总热阻 R 而非导热系数 k(多层墙要累加 δ/k) |
|
|
59
|
+
| 材料 | `metallurgy_yield` | 一眼看出「年产 5kg」与「15~20kg」差在哪 |
|
|
60
|
+
| 材料 | `case_depth` | **温度是平方级杠杆、时间是线性** |
|
|
61
|
+
| 材料 | `gear_bending_strength` | 能验算「模数 4 足以承受 30kg 重锤」 |
|
|
62
|
+
| 材料 | `gear_geometry` | d=m·z,传动比可反推齿数组合 |
|
|
63
|
+
| 传动 | `pendulum_clock_drift` | 钢摆冬夏差 20℃ 每天慢 10.4s;异星 g 变化直接可用 |
|
|
64
|
+
| 传动 | `gravity_storage_discharge` | **用途是检查设定自洽,不是算新数** |
|
|
65
|
+
| 传动 | `water_turbine_output` | 低水头大流量 → 转速慢扭矩大,能直驱锻锤 |
|
|
66
|
+
| 农业 | `gdd_accumulated` | 四季节奏的数学骨架 |
|
|
67
|
+
| 农业 | `leaching_residue` | **换水次数比泡多久更重要** |
|
|
68
|
+
| 农业 | `fermentation_time` | 温度低则 k 小、时间成倍延长 |
|
|
69
|
+
| 农业 | `syrup_concentration` | 得率只由糖度比决定,与锅火无关 |
|
|
70
|
+
|
|
71
|
+
`gravity_storage_discharge` 的定位值得单说:它**不是算新数,而是检查设定自洽**。
|
|
72
|
+
625J、8W、12 分钟各自都「看着合理」,只有放进同一个式子才暴露出差了数量级 ——
|
|
73
|
+
这类「把散落的好看数字拼起来才出错」的场景,正是公式库最该覆盖的。
|
|
74
|
+
|
|
75
|
+
### 变更(help 新增 d-process 节,27 节)
|
|
76
|
+
|
|
77
|
+
把 14 条按四条链串起来讲,每条给「什么场景该用」而不只是式子。
|
|
78
|
+
例如窑炉那条直接写「100kg 坯 20→1100℃ 本身只需 97MJ,实际耗煤对应 8~15 倍,
|
|
79
|
+
差的那部分是窑体蓄热+窑壁散热+烟气带走」。
|
|
80
|
+
|
|
81
|
+
### 过程中自己抓到的两个错
|
|
82
|
+
|
|
83
|
+
1. **`kiln_firing_time` 多除了个 60**:`heating_rate` 单位已是 K/h,ΔT/(K/h) 直接得小时。
|
|
84
|
+
写成 `/60` 后 5.4 小时的窑算成 0.09 —— 而单位栏写着 h,**数值与单位互相矛盾**。
|
|
85
|
+
这种错比纯算术错更难发现,因为 0.09 看着「像个小时间」。
|
|
86
|
+
|
|
87
|
+
2. **`module` 是保留字**(同此前的 `exports`):齿轮公式改参数名为 `gear_module`。
|
|
88
|
+
另 `growing_degree_days` 与已有公式 id 撞了,改名为 `gdd_accumulated`
|
|
89
|
+
(已有那条是单日值,新的是累计,正好互补)。
|
|
90
|
+
|
|
91
|
+
### 核实后判定「已经修好」的部分
|
|
92
|
+
|
|
93
|
+
| 反馈条目 | 实测现状 |
|
|
94
|
+
|---|---|
|
|
95
|
+
| 2.4 sanity 警告未结构化 | **已修**:`value.magnitudeWarnings` 有计数 |
|
|
96
|
+
| 2.6 批量失败原因只在文本 | **已修**:`value.items` 逐条带 `ok`/`result`/`error` |
|
|
97
|
+
| 2.7 workspace 回显只报总数 | **已修**:`value.workspace.variables` 全列,`show` 也列名 |
|
|
98
|
+
| 2.1 汉字误报(旧版) | **已修**:`1亿棵树日产台`、`年耗H2O万吨` 都不再误报 |
|
|
99
|
+
|
|
100
|
+
### 没有照做的一条
|
|
101
|
+
|
|
102
|
+
反馈建议给 `expressions` 加 `unit`/`dimension` 字段做量纲自检。**不做**,理由:
|
|
103
|
+
|
|
104
|
+
裸数字表达式的量纲**本来就不存在** —— `20000/1364` 里那两个数没有任何单位信息。
|
|
105
|
+
加 `unit` 字段等于要求调用方先声明,而他要能声明就已经知道该换成同单位了。
|
|
106
|
+
真正有效的做法是**在表达式里写单位**(`20000 kg/1364 kg`),那本来就能拦。
|
|
107
|
+
|
|
108
|
+
反馈自己也指出了正确方向:「单位统一写进表达式(自己先把吨换成 kg)」。
|
|
109
|
+
所以取舍是**不做冗余字段,守住「不猜」这条既有原则**。
|
|
110
|
+
|
|
111
|
+
### 测试
|
|
112
|
+
|
|
113
|
+
99 套 / 4912 项全绿。新增 `process-formulas.mjs` 53 项。
|
|
114
|
+
## [2.3.4] — 2026-11-08
|
|
115
|
+
|
|
116
|
+
按「总长可以扩容,但控制好一次任务的查询消耗」重做 help 结构。
|
|
117
|
+
|
|
118
|
+
### 变更(从 14 节拆成 26 节)
|
|
119
|
+
|
|
120
|
+
先测成本结构,才决定往哪扩:
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
schema 6212 字符 每轮固定付,拆节降不了 → 不动
|
|
124
|
+
目录 1083 字符 按需付一次
|
|
125
|
+
单节 800~8707 按需付 → 最贵是 domains 8707
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
所以扩容必须发生在**按需层**。当时有两节是「多个场景压在一起」:
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
domains 8707 九个互不相关的领域(梁柱/热机/流体/生态/宏观/材料/生物/财政/GDP)
|
|
132
|
+
recipe 5371 三条场景配方 + 通用手法 + 错误码,材料推演独占 2834(53%)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
查「财政赤字」要读梁柱挠度与 Péclet 数;查「帝国会不会崩」要先读 2834 字符材料链。
|
|
136
|
+
这不合理,所以拆开:
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
domains → d-struct / d-thermal / d-fluid / d-ecology / d-macro
|
|
140
|
+
d-material / d-bio / d-fiscal / d-gdp (每节 613~1553)
|
|
141
|
+
recipe → recipe / recipe-errors / recipe-fiscal
|
|
142
|
+
recipe-bio / recipe-material (每节 200~2840)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
效果:
|
|
146
|
+
|
|
147
|
+
| 指标 | 拆分前 | 拆分后 |
|
|
148
|
+
|---|---|---|
|
|
149
|
+
| 单节最大 | **8707** | **2840** |
|
|
150
|
+
| 一次典型任务(目录 + 平均节) | 3035 | **2382** |
|
|
151
|
+
| 查领域类内容 | 8707 | **613~1553** |
|
|
152
|
+
| schema(每轮固定) | 6212 | **6212(一分没涨)** |
|
|
153
|
+
| 目录 | 1083 | 1284 |
|
|
154
|
+
|
|
155
|
+
**目录多出的 201 字符,换来 12 个可独立查询的节。**
|
|
156
|
+
|
|
157
|
+
### 说明(目录怎么控制住)
|
|
158
|
+
|
|
159
|
+
12 个新节在目录里只给「key=六字标签」一行,不给标题 + 简介:
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
领域公式(各 600~1600 字符,按需查):
|
|
163
|
+
d-material=材料本构 · d-bio=生物通用 · d-struct=梁柱结构
|
|
164
|
+
推演配方(场景特定,按需查):
|
|
165
|
+
recipe-fiscal=文明崩溃链 · recipe-material=材料三层链 ...
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
若每节都给两句简介,目录会从 1083 涨到 1821 —— 那等于把「按需付费」又搬回「每次都多付」。
|
|
169
|
+
key + 六字标签足够让人知道**有这一节、叫什么**,详细内容查时再付。
|
|
170
|
+
|
|
171
|
+
### 测试
|
|
172
|
+
|
|
173
|
+
98 套 / 4843 项全绿。help-topics 从 76 项扩到 99。
|
|
174
|
+
|
|
175
|
+
四条旧断言按**原意**更新(不是降标准):
|
|
176
|
+
|
|
177
|
+
| 断言 | 改法 | 理由 |
|
|
178
|
+
|---|---|---|
|
|
179
|
+
| 目录 ≤ 1250 | → ≤ 1400 | 26 节、12 个新节压成紧凑行后实际 1284 |
|
|
180
|
+
| core 节数 9 | → 21 | 拆分产出的节都是 core(它们是公式,不是冷门功能)|
|
|
181
|
+
| core 权重中位数 > extra × 2 | → `>=` | 原判据建立在「core 只有 6 节」;真正要守的是**分档不倒挂** |
|
|
182
|
+
| 高频节简介必须在目录里 | → summary 前 10 字**或** short 在目录里 | 紧凑组只给 short,可发现性仍成立 |
|
|
183
|
+
|
|
184
|
+
schema 预算仍是硬约束且达标:`parameters` 5798/5900、总长 6212/6231、描述 414/450。
|
|
5
185
|
## [2.3.3] — 2026-11-08
|
|
6
186
|
|
|
7
187
|
针对三份实践文档(不足清单 17 条、能力评估 4 处缺口、结构性不足 8 条)
|
package/dsh.plugin.json
CHANGED
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 公式库第十四批:**工艺级工程公式**(v2.3.5)。
|
|
3
|
+
*
|
|
4
|
+
* ## 为什么单独成批
|
|
5
|
+
*
|
|
6
|
+
* 外部实测反馈(《工程公式缺口与公式库扩展建议》,2026-11-08)的核心判断:
|
|
7
|
+
*
|
|
8
|
+
* > 「公式库不是数量少(499 条),而是『工艺级工程公式』稀薄 ——
|
|
9
|
+
* > 它能算『灌溉要多少水』,算不了『掺 10% 砂的陶坯在 1100℃ 会不会裂』。」
|
|
10
|
+
*
|
|
11
|
+
* 实测分布证实了这点:
|
|
12
|
+
*
|
|
13
|
+
* ```
|
|
14
|
+
* physics 187 条 ← 极充实,解释「世界为什么这样」
|
|
15
|
+
* engineering 21 条 ← 全是顶层物理式(梁柱/热机/管流/泵)
|
|
16
|
+
* 机械 0 命中 | 发酵 0 命中 | 窑 0 命中
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* 也就是说:**已有的 187 条物理规律往下接一层就够用,缺的是那座桥。**
|
|
20
|
+
*
|
|
21
|
+
* ## 这批补的链
|
|
22
|
+
*
|
|
23
|
+
* ```
|
|
24
|
+
* 能源链 kiln_heat_balance → kiln_firing_time → wall_heat_loss
|
|
25
|
+
* 材料链 metallurgy_yield → case_depth → gear_bending_strength
|
|
26
|
+
* 传动链 gear_geometry / pendulum_clock_drift / gravity_storage_discharge
|
|
27
|
+
* 农业链 growing_degree_days → leaching_residue → fermentation_time → syrup_concentration
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* ## 一个「自洽性检查」公式的特别价值
|
|
31
|
+
*
|
|
32
|
+
* `gravity_storage_discharge` 不是为了算新数,而是**检查设定自不自洽**:
|
|
33
|
+
* 625J、8W、12 分钟各自都「看着合理」,只有放进同一个式子才暴露出差了数量级。
|
|
34
|
+
* 这类「把散落的好看数字拼起来才出错」的场景,正是公式库最该覆盖的。
|
|
35
|
+
*
|
|
36
|
+
* ## 可信度
|
|
37
|
+
*
|
|
38
|
+
* 本批多为 `phenomenological`(形式对、系数需标定)。
|
|
39
|
+
* 每个 desc 都给了典型区间与「换条件要重标定」的说明。
|
|
40
|
+
*
|
|
41
|
+
* @module dsh-math-calculator/formula-library-process
|
|
42
|
+
*/
|
|
43
|
+
const p = (value, desc) => ({ value, desc });
|
|
44
|
+
const req = (desc) => ({ value: null, desc });
|
|
45
|
+
/** 工艺级工程公式 14 条。 */
|
|
46
|
+
export const PROCESS_FORMULAS = [
|
|
47
|
+
{
|
|
48
|
+
id: 'kiln_heat_balance',
|
|
49
|
+
cat: 'engineering/process',
|
|
50
|
+
name: '窑炉热平衡(燃料热量去哪了)',
|
|
51
|
+
expr: 'ware_mass * ware_specific_heat * delta_T / 1000 * (1 + shell_loss_ratio)',
|
|
52
|
+
params: {
|
|
53
|
+
ware_mass: req('装坯质量 kg'),
|
|
54
|
+
ware_specific_heat: p(0.9, '坯体比热 kJ/(kg·K)(陶 0.8~1.1、瓷 0.9~1.3)'),
|
|
55
|
+
delta_T: req('升温幅度 K(室温→烧成温度)'),
|
|
56
|
+
shell_loss_ratio: p(12, '窑体蓄热+散热相对坯体之比(间歇窑 8~20,连续窑 3~6)'),
|
|
57
|
+
},
|
|
58
|
+
unit: 'MJ(估算的一次烧成总耗热)',
|
|
59
|
+
desc: '「单窑耗煤 Xkg」这类经验数可以靠这条验算:Q = m·c·ΔT·(1+损比)。' +
|
|
60
|
+
'★ 这是全库第一缺口 —— 有了它,耗煤量、窑衬寿命、窑型升级幅度全部可算。' +
|
|
61
|
+
'★ 实测对照:100kg 坯 20→1100℃ 本身只需 97MJ,而实际耗煤往往对应 8~15 倍,' +
|
|
62
|
+
' 差的那部分正是窑体蓄热、窑壁散热、烟气带走。' +
|
|
63
|
+
'★ 省燃料的关键在 shell_loss_ratio:间歇窑 12 是常态,' +
|
|
64
|
+
' 改连续窑/余热回收能压到 3~6 —— 这就是「窑型升级 +40%~+300%」的来源。' +
|
|
65
|
+
'⚠ 只算一次烧成的显热,不含保温维持与不完全燃烧。',
|
|
66
|
+
keys: ['窑炉', '热平衡', '耗煤', '窑体蓄热', '烧成能耗', 'kiln'],
|
|
67
|
+
frequency: 'high',
|
|
68
|
+
layer: 'phenomenological',
|
|
69
|
+
domains: ['engineering', 'materials'],
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: 'kiln_firing_time',
|
|
73
|
+
cat: 'engineering/process',
|
|
74
|
+
name: '烧成时间(升温速率受热应力限制)',
|
|
75
|
+
/**
|
|
76
|
+
* ★ 不要再除以 60 —— `heating_rate` 的单位已经是 **K/h**,
|
|
77
|
+
* 所以 ΔT/(K/h) 直接得小时。
|
|
78
|
+
*
|
|
79
|
+
* 我第一版写成 `delta_T / heating_rate / 60`,把一个 5.4 小时的窑
|
|
80
|
+
* 算成了 0.09——那看着像「5 分钟」而不是「5.4 小时」,
|
|
81
|
+
* 而单位栏还写着 h,属于**单位与数值互相矛盾**。
|
|
82
|
+
* 这类错误比纯粹的算术错更难发现,因为数值本身「看着像个小时间」。
|
|
83
|
+
*/
|
|
84
|
+
expr: 'delta_T / heating_rate',
|
|
85
|
+
params: {
|
|
86
|
+
delta_T: req('升温幅度 K'),
|
|
87
|
+
heating_rate: p(200, '安全升温速率 K/h(薄壁 150~300、厚壁 60~120)'),
|
|
88
|
+
},
|
|
89
|
+
unit: 'h(到达烧成温度所需时间)',
|
|
90
|
+
desc: 't = ΔT / 升温速率。**升温速率不是随便定的,它被热应力上限卡住。**' +
|
|
91
|
+
'★ 这就是「排潮 2h → 氧化 2.5h → 高温 2h → 保温 1h」里那些 2h 的来源:' +
|
|
92
|
+
' 不是工艺偏保守,而是厚壁件温差过大会直接开裂。' +
|
|
93
|
+
'★ 实测对照:室温→1100℃ 取 200K/h → 5.5h 爬温 + 各阶段保温,与常见「一窑一天」对得上。' +
|
|
94
|
+
'★ 关键推论:薄壁能快、厚壁必须慢 —— 壁厚翻倍,允许升温率大致降一半,工期翻倍。' +
|
|
95
|
+
'⚠ 150~300 / 60~120 是陶与瓷的常见区间;具体依热膨胀系数与抗张强度。',
|
|
96
|
+
keys: ['烧成', '升温速率', '开裂', '烧成曲线', '工期', 'firing'],
|
|
97
|
+
frequency: 'high',
|
|
98
|
+
layer: 'phenomenological',
|
|
99
|
+
domains: ['engineering', 'materials'],
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
id: 'wall_heat_loss',
|
|
103
|
+
cat: 'engineering/process',
|
|
104
|
+
name: '围护结构稳态热损(R 值法)',
|
|
105
|
+
expr: 'total_area * delta_T / r_value + ventilation_loss',
|
|
106
|
+
params: {
|
|
107
|
+
total_area: req('围护总面积 m²(墙+屋顶+地板)'),
|
|
108
|
+
delta_T: req('内外温差 K'),
|
|
109
|
+
r_value: p(2, '总热阻 R = Σ(δ/k) m²·K/W(单层砖墙 0.5,多层保温 9+)'),
|
|
110
|
+
ventilation_loss: p(0, '通风换气热损 W(可单列)'),
|
|
111
|
+
},
|
|
112
|
+
unit: 'W(维持室内温度所需加热功率)',
|
|
113
|
+
desc: 'Q = A·ΔT/R + 通风。建筑围护结构的标准算法,与工业换热器的 LMTD 完全是两回事。' +
|
|
114
|
+
'★ 关键:用总热阻 R 而不是导热系数 k,因为多层墙要逐层累加 δ/k。' +
|
|
115
|
+
'★ 实测对照:64㎡、R=9.34、ΔT=25℃ → 171W;加通风 50W 得 221W,与实测 282W 同量级' +
|
|
116
|
+
' (差异来自缝隙与热桥 —— 实际总是比计算大)。' +
|
|
117
|
+
'★ 反推用途:知道实测耗热 282W,可反推真实 R 值,检验保温做够了没有。' +
|
|
118
|
+
'⚠ R 值是灵魂:单层砖墙约 0.5,加 10cm 岩棉可到 3~4,多层真空/反射箔可达 9+。',
|
|
119
|
+
keys: ['热损', '保温', 'R值', '围护', '建筑传热', 'insulation'],
|
|
120
|
+
frequency: 'high',
|
|
121
|
+
layer: 'derived',
|
|
122
|
+
domains: ['engineering'],
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
id: 'metallurgy_yield',
|
|
126
|
+
cat: 'engineering/process',
|
|
127
|
+
name: '冶金收得率(矿石 → 金属)',
|
|
128
|
+
expr: 'ore_mass * grade * recovery',
|
|
129
|
+
params: {
|
|
130
|
+
ore_mass: req('矿石量 kg'),
|
|
131
|
+
grade: req('品位 0—1(赤铁 0.5~0.6、孔雀石 0.55~0.57)'),
|
|
132
|
+
recovery: p(0.85, '回收率(土法 0.6~0.8、改进 0.85~0.95)'),
|
|
133
|
+
},
|
|
134
|
+
unit: 'kg(产出金属量)',
|
|
135
|
+
desc: 'm = m_矿 × 品位 × 回收率。一眼就能看出「年产 5kg」与「年产 15-20kg」差在哪。' +
|
|
136
|
+
'★ 实测对照:15kg 矿 × 0.3 × 0.9 = 4.05kg 生铁;5kg 孔雀石 × 0.57 × 0.8 = 2.28kg 精铜。' +
|
|
137
|
+
'★ 反推最实用:已知「两炉年产 5kg」,反推每炉投多少矿 → 5/(2×0.35×0.7) ≈ 10kg 矿/炉。' +
|
|
138
|
+
' 数字自相矛盾时,这条能把矛盾定位到具体环节。' +
|
|
139
|
+
'★ 三因子各自可调:品位靠选矿、回收率靠炉型、矿量靠开采 ——' +
|
|
140
|
+
' 外推产能时先看哪个因子先到天花板,那才是真瓶颈。',
|
|
141
|
+
keys: ['冶金', '收得率', '品位', '回收率', '矿石', '炼铁'],
|
|
142
|
+
frequency: 'high',
|
|
143
|
+
layer: 'phenomenological',
|
|
144
|
+
domains: ['engineering', 'materials'],
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
id: 'case_depth',
|
|
148
|
+
cat: 'engineering/process',
|
|
149
|
+
name: '渗碳层深(扩散控制)',
|
|
150
|
+
expr: '2 * sqrt(D0 * exp(-activation_energy / (R * temperature)) * hold_time)',
|
|
151
|
+
params: {
|
|
152
|
+
D0: p(2e-5, '扩散常数 D₀ m²/s(碳在奥氏体铁中约 2e-5)'),
|
|
153
|
+
activation_energy: p(1.5e5, '激活能 J/mol(碳在 γ-Fe 约 1.3~1.6e5)'),
|
|
154
|
+
R: p(8.314462618, '气体常数 J/(mol·K)'),
|
|
155
|
+
temperature: req('渗碳温度 K(900℃ = 1173K)'),
|
|
156
|
+
hold_time: req('保温时间 s(3h = 10800)'),
|
|
157
|
+
},
|
|
158
|
+
unit: 'm(渗碳层深度)',
|
|
159
|
+
desc: 'x ≈ 2√(D·t),D = D₀·exp(−Q/RT)。表面硬化层的标准算法。' +
|
|
160
|
+
'★ 实测对照:900℃ 保温 3h → D≈4.2e-12 m²/s、x≈0.42mm,与「表面硬化零点几毫米」吻合。' +
|
|
161
|
+
'★ 关键推论:温度是平方级杠杆,时间是线性。' +
|
|
162
|
+
' 900→950℃ 只差 50 度,D 约翻倍,层深涨 √2 倍;而保温 3h→5h 只涨 √(5/3)≈1.29 倍。' +
|
|
163
|
+
' 所以「渗层不够就多烧一会儿」效率很低,提温才是真手段 —— 但要防过热与晶粒长大。' +
|
|
164
|
+
'⚠ D₀ 与 Q 依钢种与碳势而变,给的是低碳钢 900-950℃ 的典型区间。',
|
|
165
|
+
keys: ['渗碳', '扩散', '表面硬化', '层深', 'carburize'],
|
|
166
|
+
frequency: 'medium',
|
|
167
|
+
layer: 'derived',
|
|
168
|
+
domains: ['engineering', 'materials'],
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
id: 'gear_bending_strength',
|
|
172
|
+
cat: 'engineering/process',
|
|
173
|
+
name: '齿轮齿根弯曲强度(模数选型)',
|
|
174
|
+
expr: 'tangential_force / (face_width * gear_module * form_factor)',
|
|
175
|
+
params: {
|
|
176
|
+
tangential_force: req('圆周力 F_t N(F_t = 2T/d)'),
|
|
177
|
+
face_width: req('齿宽 b m'),
|
|
178
|
+
gear_module: req('模数 m m'),
|
|
179
|
+
form_factor: p(0.32, '齿形系数 Y(20° 标准齿 0.30~0.34)'),
|
|
180
|
+
},
|
|
181
|
+
unit: 'Pa(齿根弯曲应力;与许用弯曲应力比即判安全)',
|
|
182
|
+
desc: 'σ = F_t/(b·m·Y)。齿轮传动的强度判据,也是模数选型的依据。' +
|
|
183
|
+
'★ 这条能验算「模数 4 比 2.5 厚约 60%,足以承受 30kg 重锤」这种断言:' +
|
|
184
|
+
' m=4、z=30 → 分度圆 120mm;30kg 在 r=60mm → F_t≈294N;' +
|
|
185
|
+
' 齿宽 30mm、Y=0.32 → σ ≈ 7.7 MPa,远低于铸铁许用 30~60MPa。' +
|
|
186
|
+
'★ 结论是「模数 4 绰绰有余」,而模数 2.5 时应力涨到约 12 MPa —— 仍够。' +
|
|
187
|
+
' 所以那句断言是对的,但只有算出这两个数才知道它对。' +
|
|
188
|
+
'⚠ 简化式(未含动载系数、应力集中、齿面接触疲劳)。单件低速手工齿轮够用。',
|
|
189
|
+
keys: ['齿轮', '齿根', '弯曲强度', '模数', '选型'],
|
|
190
|
+
frequency: 'high',
|
|
191
|
+
layer: 'phenomenological',
|
|
192
|
+
domains: ['engineering'],
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
id: 'gear_geometry',
|
|
196
|
+
cat: 'engineering/process',
|
|
197
|
+
name: '齿轮几何(分度圆与传动比)',
|
|
198
|
+
expr: 'gear_module * teeth',
|
|
199
|
+
params: {
|
|
200
|
+
gear_module: req('模数 m mm'),
|
|
201
|
+
teeth: req('齿数 z'),
|
|
202
|
+
},
|
|
203
|
+
unit: 'mm(分度圆直径 d)',
|
|
204
|
+
desc: 'd = m·z。齿轮的一切尺寸都从这两个数派生:外径 d+2m、齿高 2.25m、中心距 (d₁+d₂)/2。' +
|
|
205
|
+
'★ 传动比 i = z_从/z_主(同模数)。所以「1:12 减速」可反推齿数组合:' +
|
|
206
|
+
' 单级 30:360,或两级 30:180 + 20:40 —— 单级占空间、多级效率低但紧凑,' +
|
|
207
|
+
' 这就是设计取舍的量化形式。' +
|
|
208
|
+
'★ 手工加工的约束:模数决定刀具规格,所以一个作坊只用一两种模数,' +
|
|
209
|
+
' 而齿数可自由组合 —— 「统一模数 + 自由齿数」正是钟表业的传统做法。',
|
|
210
|
+
keys: ['齿轮', '模数', '齿数', '分度圆', '传动比'],
|
|
211
|
+
frequency: 'high',
|
|
212
|
+
layer: 'derived',
|
|
213
|
+
domains: ['engineering'],
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
id: 'pendulum_clock_drift',
|
|
217
|
+
cat: 'engineering/process',
|
|
218
|
+
name: '摆钟走时精度(温度引起的快慢)',
|
|
219
|
+
expr: '86400 * (-0.5 * length_change_ratio + 0.5 * gravity_change_ratio)',
|
|
220
|
+
params: {
|
|
221
|
+
length_change_ratio: req('摆长相对变化 ΔL/L(热膨胀 α·ΔT;钢 α≈1.2e-5/K)'),
|
|
222
|
+
gravity_change_ratio: p(0, '重力相对变化 Δg/g(同地可忽略,高原/异星要算)'),
|
|
223
|
+
},
|
|
224
|
+
unit: 's/天(正为走快,负为走慢)',
|
|
225
|
+
desc: 'T = 2π√(L/g),取对数微分得 ΔT/T = −½·ΔL/L + ½·Δg/g,乘 86400 得每天偏差。' +
|
|
226
|
+
'★ 实测对照:钢摆 α=1.2e-5、冬夏温差 20℃ → ΔL/L=2.4e-4 → 每天慢约 10.4 秒。' +
|
|
227
|
+
' 这就是「摆钟冬夏要重新校」的定量原因,也是补偿摆(双金属)要解决的问题。' +
|
|
228
|
+
'★ 重要推论:周期只与摆长的**平方根**有关,所以摆长误差的影响被压掉一半;' +
|
|
229
|
+
' 摆长差 0.1% 只让每天差 43 秒 —— 天文观测完全够用来校准。' +
|
|
230
|
+
'★ 反过来最有用:**异星设定**里 g 变了多少,钟就快慢多少,这条直接给数。' +
|
|
231
|
+
'⚠ 补偿摆能压到每天 1~2 秒;真空+恒温的精密摆钟可到每天 0.01 秒。',
|
|
232
|
+
keys: ['摆钟', '钟表', '走时', '精度', '热膨胀'],
|
|
233
|
+
frequency: 'medium',
|
|
234
|
+
layer: 'derived',
|
|
235
|
+
domains: ['engineering'],
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
id: 'gravity_storage_discharge',
|
|
239
|
+
cat: 'engineering/process',
|
|
240
|
+
name: '重力储能放电时长(自洽性检查)',
|
|
241
|
+
expr: 'mass * 9.80665 * height / power',
|
|
242
|
+
params: {
|
|
243
|
+
mass: req('配重质量 kg'),
|
|
244
|
+
height: req('落差 m'),
|
|
245
|
+
power: req('放电功率 W'),
|
|
246
|
+
},
|
|
247
|
+
unit: 's(能维持该功率的时长)',
|
|
248
|
+
desc: 't = E/P = m·g·h/P。**最重要的用途是检查设定自不自洽,而不是算新数。**' +
|
|
249
|
+
'★ 实测对照(外部反馈的原案例):25kg 配重 × 2.5m = 625J;' +
|
|
250
|
+
' 若设定说「6~8W 持续 12~15 分钟」,625J ÷ 8W = 78 秒 —— 差一个数量级。' +
|
|
251
|
+
'★ 这种错误极难自察:625J、8W、12 分钟各自都「看着合理」,' +
|
|
252
|
+
' 只有把三个数放进同一个式子才暴露。这正是能量守恒检查的价值。' +
|
|
253
|
+
'★ 反推用途:要维持 8W 共 12 分钟需 5760J → 需 235kg×2.5m 或 25kg×23.5m。' +
|
|
254
|
+
' 于是「要么加配重十倍、要么加高十倍」—— 设计方向一下就明确了。',
|
|
255
|
+
keys: ['重力储能', '配重', '放电', '储能时长', '自洽检查'],
|
|
256
|
+
frequency: 'high',
|
|
257
|
+
layer: 'fundamental',
|
|
258
|
+
domains: ['engineering', 'physics'],
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
id: 'water_turbine_output',
|
|
262
|
+
cat: 'engineering/process',
|
|
263
|
+
name: '水轮输出(功率/扭矩/转速)',
|
|
264
|
+
expr: 'density * 9.80665 * flow * head * efficiency',
|
|
265
|
+
params: {
|
|
266
|
+
density: p(1000, '水密度 kg/m³'),
|
|
267
|
+
flow: req('流量 m³/s'),
|
|
268
|
+
head: req('有效水头 m'),
|
|
269
|
+
efficiency: p(0.7, '总效率(木制水轮 0.4~0.6、改进 0.7~0.85)'),
|
|
270
|
+
},
|
|
271
|
+
unit: 'W(轴输出功率)',
|
|
272
|
+
desc: 'P = ρgQHη。与水轮机的「泵」公式同形但方向相反 —— 泵用电换水头,水轮用水头换功。' +
|
|
273
|
+
'★ 实测对照:溪流 0.01m³/s、水头 3m、η=0.6 → 176W;小河 0.1m³/s、水头 6m → 3.5kW。' +
|
|
274
|
+
'★ 扭矩 T = P/ω,转速 n = 60v/(πD):' +
|
|
275
|
+
' 低水头大流量的水轮转速慢、扭矩大,**这正是它能直接带动锻锤的原因**;' +
|
|
276
|
+
' 而带动锯需要高转速,得加增速传动 —— 于是「传动比」成了必需项而不是选择项。' +
|
|
277
|
+
'★ 效率 0.4→0.85 就是「木轮改铁轮 + 导流」的全部收益,提升 2 倍。',
|
|
278
|
+
keys: ['水轮', '水车', '水力', '功率', '扭矩'],
|
|
279
|
+
frequency: 'high',
|
|
280
|
+
layer: 'derived',
|
|
281
|
+
domains: ['engineering'],
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
id: 'gdd_accumulated',
|
|
285
|
+
cat: 'engineering/process',
|
|
286
|
+
name: '累计生长度日(一季能攒多少积温)',
|
|
287
|
+
expr: 'excess_daily_temp * days',
|
|
288
|
+
params: {
|
|
289
|
+
excess_daily_temp: p(10, '日均温超出基点部分 K(日均 20℃、基点 10℃ → 10)'),
|
|
290
|
+
days: req('生育期天数(无霜期 180~210)'),
|
|
291
|
+
},
|
|
292
|
+
unit: '℃·d(生长度日 GDD)',
|
|
293
|
+
desc: 'GDD = Σ max(0, T_日均 − T_基点)。**四季节奏的数学骨架。**' +
|
|
294
|
+
'★ 价值在于「把时间换算成热量」:同样 200 天生育期,' +
|
|
295
|
+
' 暖地日均积 15 度、冷地 8 度 → GDD 差近 2 倍 → 能种的作物完全不同。' +
|
|
296
|
+
'★ 实测用途:给定「无霜期 180~210 天」可反推这一季能攒多少积温,' +
|
|
297
|
+
' 再对照作物需求(玉米 2500~2800、小麦 1800~2200、水稻 3000+)判断能不能熟。' +
|
|
298
|
+
'★ 这也是「春播秋收冬藏」必须按日历走的定量理由 —— 积温不够就熟不了。' +
|
|
299
|
+
'⚠ 基点温度依作物而变(小麦 0~5℃、玉米 10℃、水稻 10~12℃)。',
|
|
300
|
+
keys: ['生长度日', 'GDD', '积温', '物候', '无霜期', '农业'],
|
|
301
|
+
frequency: 'medium',
|
|
302
|
+
layer: 'phenomenological',
|
|
303
|
+
domains: ['agriculture', 'biology'],
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
id: 'leaching_residue',
|
|
307
|
+
cat: 'engineering/process',
|
|
308
|
+
name: '浸提残留(换水去单宁/苦涩)',
|
|
309
|
+
expr: 'initial_concentration * residual_ratio^changes',
|
|
310
|
+
params: {
|
|
311
|
+
initial_concentration: req('初始浓度(如单宁含量)'),
|
|
312
|
+
residual_ratio: p(0.6, '每次换水后的残留比(0.5~0.7,依切块大小与水温)'),
|
|
313
|
+
changes: req('换水次数'),
|
|
314
|
+
},
|
|
315
|
+
unit: '与初始浓度同单位',
|
|
316
|
+
desc: 'C_n = C₀·rⁿ。橡子、蕨根、苦杏仁去毒去涩的标准算法。' +
|
|
317
|
+
'★ 实测对照:r=0.6 换 4 次 → 0.1296,残留 13%;换 5 次 7.8%、换 6 次 4.7% —— 指数衰减。' +
|
|
318
|
+
'★ 关键推论:**换水次数比每次泡多久更重要。**' +
|
|
319
|
+
' 泡一夜再换 4 次(0.13)远好于泡 4 天不换(几乎不衰减)——' +
|
|
320
|
+
' 因为扩散平衡后浓度不再下降,必须靠换水把平衡点推下去。' +
|
|
321
|
+
'★ 这也是「手工程序值得公式化」的最好例子:' +
|
|
322
|
+
' 设定里写「需浸泡去单宁」但没给次数,而次数直接决定能不能吃。',
|
|
323
|
+
keys: ['浸提', '去单宁', '浸泡', '换水', '脱毒', 'leaching'],
|
|
324
|
+
frequency: 'medium',
|
|
325
|
+
layer: 'derived',
|
|
326
|
+
domains: ['agriculture', 'chemistry'],
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
id: 'fermentation_time',
|
|
330
|
+
cat: 'engineering/process',
|
|
331
|
+
name: '发酵时间(达到目标残留糖)',
|
|
332
|
+
expr: '-(log(target_residual / initial_sugar)) / rate_constant',
|
|
333
|
+
params: {
|
|
334
|
+
initial_sugar: req('初始糖浓度'),
|
|
335
|
+
target_residual: req('目标残留糖浓度'),
|
|
336
|
+
rate_constant: p(0.07, '速率常数 k 1/day(酿酒 0.05~0.09、酿醋 0.02~0.04)'),
|
|
337
|
+
},
|
|
338
|
+
unit: 'day(达到目标残留糖所需天数)',
|
|
339
|
+
desc: 'S(t) = S₀·e^(−kt),解出 t = −ln(S_残/S₀)/k。酿酒、酿醋、沤肥的时间估算。' +
|
|
340
|
+
'★ 实测对照:降到 5%、k=0.07 → t = −ln(0.05)/0.07 ≈ 43 天;' +
|
|
341
|
+
' 而 k=0.04(低温)需 75 天 —— **这就是「温度低一度要延长几天」的定量答案。**' +
|
|
342
|
+
'★ 关键推论:发酵时间对温度极敏感(k 随温度按 Q₁₀ 律变,见 q10_temperature)。' +
|
|
343
|
+
' 所以「酿酒 2~4 周、酿醋 6~8 周」不是随便写的,它对应两个不同的 k。' +
|
|
344
|
+
'★ 串联用途:先用 q10_temperature 由温度得 k,再代入本式得工期 —— 这是「换季要改工艺」的可算理由。' +
|
|
345
|
+
'⚠ 简化的一级动力学;实际发酵有滞后期与产物抑制,工业上要用 Monod + 抑制项。',
|
|
346
|
+
keys: ['发酵', '酿酒', '酿醋', '沤肥', '时间', 'fermentation'],
|
|
347
|
+
frequency: 'medium',
|
|
348
|
+
layer: 'derived',
|
|
349
|
+
domains: ['agriculture', 'biology', 'chemistry'],
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
id: 'syrup_concentration',
|
|
353
|
+
cat: 'engineering/process',
|
|
354
|
+
name: '熬煮浓缩(糖浆得率)',
|
|
355
|
+
expr: 'juice_volume * initial_brix / final_brix',
|
|
356
|
+
params: {
|
|
357
|
+
juice_volume: req('原汁体积 L'),
|
|
358
|
+
initial_brix: req('初始糖度 Brix(%)'),
|
|
359
|
+
final_brix: req('成品糖度 Brix(%)'),
|
|
360
|
+
},
|
|
361
|
+
unit: 'L(成品体积)',
|
|
362
|
+
desc: 'V_f = V₀·Brix₀/Brix_f。糖量守恒的浓缩换算。' +
|
|
363
|
+
'★ 实测对照:40L 枫汁 Brix=2.5、成品 66 → 40×2.5/66 = 1.52L。' +
|
|
364
|
+
' 设定里「40L 产 1L 糖浆」对应成品 Brix 更高或含水更多,量级一致。' +
|
|
365
|
+
'★ 关键推论:**浓缩比只由糖度比决定**,与锅的大小、火的大小都无关。' +
|
|
366
|
+
' 所以「熬多久」只影响风味与色泽,不影响得率 —— 得率只看两个度数。' +
|
|
367
|
+
'★ 反过来最实用:知道要熬到多少度,就能预估这一锅能出多少,' +
|
|
368
|
+
' 这也是判断「值不值得熬」的依据(燃料成本 vs 成品收益)。' +
|
|
369
|
+
'⚠ Brix 是质量百分比糖度;若用糖度计读数,需按温度修正。',
|
|
370
|
+
keys: ['熬煮', '浓缩', '糖浆', 'Brix', '糖度', '得率'],
|
|
371
|
+
frequency: 'medium',
|
|
372
|
+
layer: 'derived',
|
|
373
|
+
domains: ['agriculture', 'chemistry'],
|
|
374
|
+
}
|
|
375
|
+
];
|
package/lib/formulas.js
CHANGED
|
@@ -23,6 +23,7 @@ import { ENGINEERING_FORMULAS } from './formula-library-engineering.js';
|
|
|
23
23
|
import { BIOECON_FORMULAS } from './formula-library-bioecon.js';
|
|
24
24
|
import { MACRO_MATERIAL_FORMULAS } from './formula-library-macro-materials.js';
|
|
25
25
|
import { BIO_GENERAL_FORMULAS } from './formula-library-biol-general.js';
|
|
26
|
+
import { PROCESS_FORMULAS } from './formula-library-process.js';
|
|
26
27
|
import { getActiveConstants } from './constants-graph.js';
|
|
27
28
|
import { loadGlobalFormulas } from './formula-pack.js';
|
|
28
29
|
import { findUnit, convert } from './units.js';
|
|
@@ -45,6 +46,7 @@ export const FORMULAS = [
|
|
|
45
46
|
...BIOECON_FORMULAS,
|
|
46
47
|
...MACRO_MATERIAL_FORMULAS,
|
|
47
48
|
...BIO_GENERAL_FORMULAS,
|
|
49
|
+
...PROCESS_FORMULAS,
|
|
48
50
|
];
|
|
49
51
|
/** id 索引(后批次覆盖同名 id 时以后者为准,便于后续修订)。 */
|
|
50
52
|
export const FORMULA_INDEX = new Map();
|
|
@@ -85,6 +87,8 @@ for (const formula of MACRO_MATERIAL_FORMULAS)
|
|
|
85
87
|
FORMULA_INDEX.set(formula.id, formula);
|
|
86
88
|
for (const formula of BIO_GENERAL_FORMULAS)
|
|
87
89
|
FORMULA_INDEX.set(formula.id, formula);
|
|
90
|
+
for (const formula of PROCESS_FORMULAS)
|
|
91
|
+
FORMULA_INDEX.set(formula.id, formula);
|
|
88
92
|
/**
|
|
89
93
|
* 把全局公式包并入内置公式(幂等:已存在的 id 跳过)。
|
|
90
94
|
*
|
package/lib/guards.js
CHANGED
|
@@ -83,8 +83,36 @@ export function magnitudeOfLabel(label) {
|
|
|
83
83
|
*/
|
|
84
84
|
let body = text;
|
|
85
85
|
const bracketPair = body.match(/[((\[【]\s*(.+?)\s*[))\]】]$/);
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
/**
|
|
87
|
+
* ## 括号前还有描述文字时,括号内是**输入条件**,不是结果单位
|
|
88
|
+
*
|
|
89
|
+
* 实测反馈(2026-11-08 第二份):
|
|
90
|
+
*
|
|
91
|
+
* ```
|
|
92
|
+
* label:"煤储量/年耗 可支撑年数(2万吨)" expr:"20000/1.364" → 14662.75
|
|
93
|
+
* → ⚠ label 含「万」,而结果 14662 本身已达 10⁴;若按字面读成「万」则为 1.47e8
|
|
94
|
+
* ```
|
|
95
|
+
*
|
|
96
|
+
* 而作者的真实意思是「**2 万吨煤**能支撑多少年」—— 括号里是那个煤量的口径说明,
|
|
97
|
+
* 不是「结果单位是万吨」。这条警告纯属噪声,而且会把真正的量纲问题盖过去。
|
|
98
|
+
*
|
|
99
|
+
* 判据:成对括号**在末尾**,但括号**前面还有非空白文字**,且那段文字里有
|
|
100
|
+
* 中文描述(不是纯数字/符号),则括号内是条件描述,直接放过。
|
|
101
|
+
*
|
|
102
|
+
* 保留的正当情形:`年发电量(亿)` —— 括号前是「年发电量」这个**量名**,
|
|
103
|
+
* 括号里是它的单位。所以还要排除「括号前那段是纯量名(不含数字、不含斜杠)」…
|
|
104
|
+
* 太细了,实测两类写法都出现,所以这里取一个更稳的折衷:
|
|
105
|
+
* **括号内含数字 + 量级词 + 单位词**(如 `2万吨`、`300万件`)→ 判为条件;
|
|
106
|
+
* **括号内只有量级词 + 单位词**(如 `亿`、`万吨`)→ 仍按结果单位处理。
|
|
107
|
+
*/
|
|
108
|
+
if (bracketPair) {
|
|
109
|
+
const inner = bracketPair[1].trim();
|
|
110
|
+
const hasQuantity = /^[0-9][0-9,.]*\s*/.test(inner);
|
|
111
|
+
if (!hasQuantity)
|
|
112
|
+
body = inner;
|
|
113
|
+
else
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
88
116
|
/**
|
|
89
117
|
* ## 判据:量级词必须处在「单位位置」
|
|
90
118
|
*
|