Files
AutoBOM/docs/Test_PP_06_FullIntegration_流程详解.md
Misaka_Company 3a93459002
All checks were successful
NTFY Notification / notify (push) Successful in 5s
feat: add preprocessing module for BOM condition transformation
Add M05_PreProcessor module to handle value mapping and condition
simplification for "接头" category before parsing.

Features:
- Value mapping: azxs codes (A0/AT/AH→径向, B0/BT/BZ/BH→下轴向,
  Z0/ZT/ZZ/ZH→中轴向) and lcfw ranges (M01-M11→低压, M12-M16→高压)
- OR condition merging: automatically removes duplicate OR segments
- Smart parentheses handling: removes parentheses for single atoms,
  preserves them when needed for logical structure
- Recursive nested expression processing
- Graceful degradation when "对照表" worksheet is missing

Integration:
- Modified M01_Main to initialize preprocessor after M03_Logic
- Preprocessing applied only for "接头" category
- Updated M99_TestRunner with 8 comprehensive test cases
- All tests passing (50 total: 42 core + 8 preprocessing)

Documentation:
- Added detailed flow documentation for Test_PP_06_FullIntegration
  with mermaid diagrams in docs/Test_PP_06_FullIntegration_流程详解.md
- Updated CLAUDE.md with preprocessing module description and
  documentation guidelines (docs/ vs reference_docs/)

Example transformation:
  Input:  gclj=M16 AND (azxs=A0 OR azxs=AT) AND (lcfw=M01 OR lcfw=M15)
  Output: gclj=M16 AND azxs=径向 AND (lcfw=低压 OR lcfw=高压)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-09 16:24:41 +08:00

709 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Test_PP_06_FullIntegration 流程详解
## 目录
1. [测试概述](#测试概述)
2. [测试场景](#测试场景)
3. [完整执行流程](#完整执行流程)
4. [详细步骤分析](#详细步骤分析)
5. [关键数据结构](#关键数据结构)
6. [映射表说明](#映射表说明)
---
## 测试概述
**测试名称**: `Test_PP_06_FullIntegration` (完整集成测试)
**测试目的**: 验证预处理模块与逻辑解析模块的完整集成,确保:
1. 值映射功能正确azxs 和 lcfw
2. 嵌套 OR 条件正确简化
3. 复杂表达式的括号正确处理
4. 预处理后的结果能被 M03_Logic 正确解析
**涉及模块**:
- M05_PreProcessor (预处理模块)
- M03_Logic (逻辑解析模块)
- clsErrorLogger (错误日志)
---
## 测试场景
### 输入条件
```
gclj=M16 AND (azxs=A0 OR azxs=AT) AND (lcfw=M01 OR lcfw=M15)
```
### 预期预处理结果
```
gclj=M16 AND azxs=径向 AND (lcfw=低压 OR lcfw=高压)
```
### 预期解析结果
生成 **2 行**数据:
- **行 1**: gclj=M16, azxs=径向, lcfw=低压
- **行 2**: gclj=M16, azxs=径向, lcfw=高压
### 关键验证点
1.`azxs=A0 OR azxs=AT``azxs=径向` (两个值映射相同,去重)
2.`(lcfw=M01 OR lcfw=M15)``(lcfw=低压 OR lcfw=高压)` (值映射,保留括号)
3. ✓ 最终生成 2 行数据
---
## 完整执行流程
### 流程总览
```mermaid
flowchart TD
Start[开始测试] --> Setup[初始化测试环境]
Setup --> LoadMapping[加载映射表]
LoadMapping --> CallPreprocessor[调用 PreprocessCondition]
CallPreprocessor --> CheckCategory{类别 = 接头?}
CheckCategory -->|否| ReturnOriginal[返回原条件]
CheckCategory -->|是| ProcessNested[递归处理嵌套表达式]
ProcessNested --> ProcessFirstBracket[处理第一个括号<br/>azxs=A0 OR azxs=AT]
ProcessFirstBracket --> ApplyPreprocess1[应用预处理]
ApplyPreprocess1 --> ReplaceAzxs[值替换: azxs映射]
ReplaceAzxs --> MergeOR1[合并重复OR]
MergeOR1 --> CheckParens1{需要括号?}
CheckParens1 -->|否| NoParens1[去掉括号<br/>azxs=径向]
CheckParens1 -->|是| KeepParens1[保留括号]
NoParens1 --> ProcessSecondBracket[处理第二个括号<br/>lcfw=M01 OR lcfw=M15]
KeepParens1 --> ProcessSecondBracket
ProcessSecondBracket --> ApplyPreprocess2[应用预处理]
ApplyPreprocess2 --> ReplaceLcfw[值替换: lcfw映射]
ReplaceLcfw --> MergeOR2[合并重复OR检查]
MergeOR2 --> CheckParens2{需要括号?}
CheckParens2 -->|否| NoParens2[去掉括号]
CheckParens2 -->|是| KeepParens2[保留括号<br/>lcfw=低压 OR lcfw=高压]
NoParens2 --> FinalProcess[最终AND分段处理]
KeepParens2 --> FinalProcess
FinalProcess --> ReturnPreprocessed[返回预处理结果]
ReturnPreprocessed --> ParseRule[M03_Logic.ParseRule解析]
ParseRule --> SplitTopLevelOR{顶层OR分割}
SplitTopLevelOR --> SplitOR[分割: 2个OR分段]
SplitOR --> ParseEachOR[解析每个OR分段]
ParseEachOR --> VerifyResults{验证结果}
VerifyResults -->|count=2| Success[测试通过]
VerifyResults -->|count≠2| Failure[测试失败]
```
### 函数调用时序图
```mermaid
sequenceDiagram
participant Test as Test_PP_06
participant PP as M05_PreProcessor
participant Logic as M03_Logic
participant Mapping as 映射表
Test->>PP: InitPreProcessor(logger, wsMapping)
PP->>Mapping: LoadLcfwMapping()
Mapping-->>PP: lcfw映射表加载
PP->>Mapping: LoadAzxsMapping()
Mapping-->>PP: azxs映射表加载
Test->>PP: PreprocessCondition(inputCond, "接头", 1)
Note over PP: 步骤1: 类别检查
alt 类别 != "接头"
PP-->>Test: 返回原条件
else 类别 == "接头"
PP->>PP: ApplyPreprocessing()
Note over PP: 步骤2: 递归处理嵌套括号
PP->>PP: ProcessAndSimplifyNested()
Note over PP: 处理 (azxs=A0 OR azxs=AT)
PP->>PP: 提取括号内容
PP->>PP: ApplyPreprocessing(azxs=A0 OR azxs=AT)
PP->>PP: 分割OR: [azxs=A0, azxs=AT]
PP->>PP: ProcessAndSegment(azxs=A0)
PP->>Mapping: 查询 azxs="A0"
Mapping-->>PP: 返回 "径向"
PP->>PP: ProcessAndSegment(azxs=AT)
PP->>Mapping: 查询 azxs="AT"
Mapping-->>PP: 返回 "径向"
PP->>PP: MergeDuplicateORs()
Note over PP: 两段相同 → 返回一段
PP->>PP: SimplifyIfAllSame()
Note over PP: 检查: 无顶层OR → 去掉括号
PP-->>PP: azxs=径向
Note over PP: 处理 (lcfw=M01 OR lcfw=M15)
PP->>PP: 提取括号内容
PP->>PP: ApplyPreprocessing(lcfw=M01 OR lcfw=M15)
PP->>PP: 分割OR: [lcfw=M01, lcfw=M15]
PP->>PP: ProcessAndSegment(lcfw=M01)
PP->>Mapping: 查询 lcfw="M01"
Mapping-->>PP: 返回 "低压"
PP->>PP: ProcessAndSegment(lcfw=M15)
PP->>Mapping: 查询 lcfw="M15"
Mapping-->>PP: 返回 "高压"
PP->>PP: MergeDuplicateORs()
Note over PP: 两段不同 → 保留两段
PP->>PP: SimplifyIfAllSame()
Note over PP: 检查: 有顶层OR → 保留括号
PP-->>PP: (lcfw=低压 OR lcfw=高压)
Note over PP: 步骤3: 最终AND处理
PP->>PP: ProcessAndSegment(完整表达式)
PP-->>Test: gclj=M16 AND azxs=径向 AND (lcfw=低压 OR lcfw=高压)
end
Test->>Logic: ParseRule(preprocessed, 1)
Note over Logic: 步骤4: 逻辑解析
Logic->>Logic: RecursiveParse()
Note over Logic: 查找顶层OR
Logic->>Logic: FindSplitIndex(OR)
Note over Logic: 找到: (lcfw=低压 OR lcfw=高压) 之前
Logic->>Logic: 递归解析左段
Note over Logic: gclj=M16 AND azxs=径向
Logic->>Logic: 解析AND → 笛卡尔积
Logic-->>Logic: Row1: {gclj:M16, azxs:径向}
Logic->>Logic: 递归解析右段
Note over Logic: lcfw=低压 OR lcfw=高压
Logic->>Logic: 解析OR → 并集
Logic-->>Logic: Row2: {lcfw:低压}, Row3: {lcfw:高压}
Logic->>Logic: CartesianProduct(Row1, Row2)
Note over Logic: 笛卡尔积: 1 × 2 = 2行
Logic-->>Logic: RowA: {gclj:M16, azxs:径向, lcfw:低压}
Logic-->>Logic: RowB: {gclj:M16, azxs:径向, lcfw:高压}
Logic-->>Test: Collection(2行)
Note over Test: 步骤5: 验证结果
Test->>Test: col.count == 2 ?
Test->>Test: row("gclj") == "M16" ?
Test->>Test: row("azxs") == "径向" ?
Test->>Test: row("lcfw") == "低压" ?
Test-->>Test: ✓ 测试通过
```
---
## 详细步骤分析
### 步骤 1: 初始化测试环境
```vba
Private Sub Test_PP_06_FullIntegration()
SetupPreProcessorTest
```
**执行动作**:
1. 查找 `[对照表]` 工作表
2. 创建 `clsErrorLogger` 实例
3. 初始化 `M03_Logic` 模块
4. 初始化 `M05_PreProcessor` 模块
**数据结构初始化**:
```vba
Set g_LcfwMapping = CreateObject("Scripting.Dictionary")
Set g_AzxsMapping = CreateObject("Scripting.Dictionary")
```
### 步骤 2: 加载映射表
**LoadAzxsMapping() 执行流程**:
```mermaid
flowchart LR
Start[开始加载azxs映射] --> Read[读取 D列:E列<br/>行3到最后]
Read --> Process[逐行处理]
Process --> Check{有数据?}
Check -->|是| Extract[提取key和value<br/>例: D3=A0, E3=径向]
Check -->|否| Next[下一行]
Extract --> Add[添加到Dictionary<br/>g_AzxsMapping.Add A0, 径向]
Add --> Next
Next --> More{还有行?}
More -->|是| Process
More -->|否| End[结束]
```
**加载的 azxs 映射数据**:
```javascript
g_AzxsMapping = {
"A0": "径向",
"AT": "径向",
"AH": "径向",
"B0": "下轴向",
"BT": "下轴向",
"BZ": "下轴向",
"BH": "下轴向",
"Z0": "中轴向",
"ZT": "中轴向",
"ZZ": "中轴向",
"ZH": "中轴向"
}
```
**LoadLcfwMapping() 执行流程**:
```javascript
g_LcfwMapping = {
"M01": "低压",
"M02": "低压",
"M03": "低压",
"M04": "低压",
"M05": "低压",
"M06": "低压",
"M07": "低压",
"M08": "低压",
"M09": "低压",
"M10": "低压",
"M11": "低压",
"M12": "高压", // 假设M12映射到高压
"M13": "高压", // 假设M13映射到高压
"M14": "高压",
"M15": "高压",
"M16": "高压"
}
```
### 步骤 3: 预处理入口
```vba
inputCond = "gclj=M16 AND (azxs=A0 OR azxs=AT) AND (lcfw=M01 OR lcfw=M15)"
preprocessed = M05_PreProcessor.PreprocessCondition(inputCond, "接头", 1)
```
**PreprocessCondition() 执行流程**:
```mermaid
flowchart TD
Start[PreprocessCondition] --> CheckInit{初始化?}
CheckInit -->|否| Return1[返回原条件]
CheckInit -->|是| CheckCat{类别=接头?}
CheckCat -->|否| Return2[返回原条件]
CheckCat -->|是| Apply[ApplyPreprocessing]
Apply --> Return3[返回预处理结果]
```
**检查结果**:
- ✓ 已初始化: `g_IsInitialized = True`
- ✓ 类别匹配: `strCategory = "接头"`
- → 继续执行 `ApplyPreprocessing()`
### 步骤 4: 递归处理嵌套表达式
#### 4.1 ProcessAndSimplifyNested() 处理第一个括号
**输入字符串**: `gclj=M16 AND (azxs=A0 OR azxs=AT) AND (lcfw=M01 OR lcfw=M15)`
**逐字符处理流程**:
```mermaid
flowchart TD
Start[开始处理] --> P0[处理字符 1-12<br/>gclj=M16 AND]
P0 --> P1[字符 13: 遇到左括号]
P1 --> B1[bracketLevel = 1<br/>进入括号模式]
B1 --> Collect[收集字符 14-28<br/>azxs=A0 OR azxs=AT]
Collect --> B2[字符 29: 遇到右括号]
B2 --> Recurse[递归处理括号内容]
Recurse --> Recurse1[ProcessAndSimplifyNested<br/>无嵌套括号]
Recurse1 --> Apply1[ApplyPreprocessing]
Apply1 --> Split1[SplitTopLevel OR]
Split1 --> Seg1[分段: azxs=A0]
Split1 --> Seg2[分段: azxs=AT]
Seg1 --> Proc1[ProcessAndSegment]
Seg2 --> Proc2[ProcessAndSegment]
Proc1 --> Atom1[ProcessAtom: azxs=A0]
Proc2 --> Atom2[ProcessAtom: azxs=AT]
Atom1 --> Map1[查询: A0→径向]
Atom2 --> Map2[查询: AT→径向]
Map1 --> Res1[azxs=径向]
Map2 --> Res2[azxs=径向]
Res1 --> Merge[MergeDuplicateORs]
Res2 --> Merge
Merge --> Simplify[SimplifyIfAllSame]
Simplify --> Check{两段相同?}
Check -->|是| Single[返回单段<br/>azxs=径向]
Check -->|否| Both[保留OR]
Single --> Need{需要括号?}
Both --> Need
Need --> HasOp[HasTopLevelOperator]
HasOp --> NoOp[无顶层操作符]
NoOp --> NoParens[needsParens = False]
NoParens --> Append[添加到结果<br/>azxs=径向]
Append --> Continue[继续处理后续字符]
```
**第一个括号处理结果**:
```
(azxs=A0 OR azxs=AT) → azxs=径向
```
**为什么去掉括号?**
- 处理后内容: `azxs=径向`
- 检查顶层操作符: 无 OR, 无 AND
- 结论: 单个原子,不需要括号
#### 4.2 ProcessAndSimplifyNested() 处理第二个括号
**输入字符串**: `(lcfw=M01 OR lcfw=M15)`
**处理流程**:
```mermaid
flowchart TD
Start[处理 lcfw括号] --> Extract[提取内容]
Extract --> Content[内容: lcfw=M01 OR lcfw=M15]
Content --> Recursive[递归处理<br/>ProcessAndSimplifyNested]
Recursive --> Apply[ApplyPreprocessing]
Apply --> Split[SplitTopLevel OR]
Split --> Segments[分段: 2个元素]
Segments --> Seg1[分段1: lcfw=M01]
Segments --> Seg2[分段2: lcfw=M15]
Seg1 --> Process1[ProcessAndSegment M01]
Seg2 --> Process2[ProcessAndSegment M15]
Process1 --> Map1[查询映射: M01→低压]
Process2 --> Map2[查询映射: M15→高压]
Map1 --> Merge1[MergeDuplicateORs]
Map2 --> Merge1
Merge1 --> CheckSame{两段相同?}
CheckSame -->|否| KeepBoth[保留两段]
KeepBoth --> Simplify[SimplifyIfAllSame]
Simplify --> CheckParens{需要括号?}
CheckParens --> HasOR[HasTopLevelOperator检查]
HasOR --> HasResult[返回 True: 有顶层OR]
HasResult --> AddParens[添加括号]
AddParens --> Final[最终结果<br/>lcfw=低压 OR lcfw=高压]
```
**第二个括号处理结果**:
```
(lcfw=M01 OR lcfw=M15) → (lcfw=低压 OR lcfw=高压)
```
**为什么保留括号?**
- 处理后内容: `lcfw=低压 OR lcfw=高压`
- 检查顶层操作符: 有 OR
- 结论: 有顶层操作符,需要括号以保持正确逻辑结构
### 步骤 5: 最终表达式组装
**当前状态**:
- 原始: `gclj=M16 AND (azxs=A0 OR azxs=AT) AND (lcfw=M01 OR lcfw=M15)`
- 第一个括号处理后: `gclj=M16 AND azxs=径向 AND (lcfw=M01 OR lcfw=M15)`
- 第二个括号处理后: `gclj=M16 AND azxs=径向 AND (lcfw=低压 OR lcfw=高压)`
**最终预处理结果**:
```
gclj=M16 AND azxs=径向 AND (lcfw=低压 OR lcfw=高压)
```
### 步骤 6: M03_Logic.ParseRule 解析
#### 6.1 递归解析流程
```mermaid
flowchart TD
Start[ParseRule] --> Clean[CleanString]
Clean --> Recursive[RecursiveParse]
Recursive --> FindOR[FindSplitIndex OR]
FindOR --> FoundOR{找到OR}
FoundOR -->|是| SplitOR[分割位置]
FoundOR -->|否| FindAND[FindSplitIndex AND]
SplitOR --> Left[左段解析]
SplitOR --> Right[右段解析]
Left --> ParseLeft[RecursiveParse左段]
ParseLeft --> FindAND1[FindSplitIndex AND]
FindAND1 --> FoundAND1{找到AND}
FoundAND1 -->|是| SplitAND[分割AND]
SplitAND --> LeftLeft[元素1 gclj=M16]
SplitAND --> LeftRight[元素2 azxs=径向]
LeftLeft --> Atom1[ParseAtom字典1]
LeftRight --> Atom2[ParseAtom字典2]
Atom1 --> Merge1[MergeDictionaries]
Atom2 --> Merge1
Merge1 --> Result1[合并结果<br/>gclj为M16和azxs为径向]
Right --> ParseRight[RecursiveParse右段]
ParseRight --> FindOR2[FindSplitIndex OR]
FindOR2 --> FoundOR2{找到OR}
FoundOR2 -->|是| SplitOR2[分割OR]
SplitOR2 --> RightLeft[元素1 lcfw=低压]
SplitOR2 --> RightRight[元素2 lcfw=高压]
RightLeft --> Atom3[ParseAtom字典3]
RightRight --> Atom4[ParseAtom字典4]
Atom3 --> Union1[UnionCollections]
Atom4 --> Union1
Union1 --> Result2[Collection集合<br/>包含2个字典元素]
Result1 --> Cartesian[笛卡尔积计算]
Result2 --> Cartesian
Cartesian --> Final[最终结果<br/>2行数据]
```
#### 6.2 笛卡尔积计算
**输入**:
- 左段: 1行 → `[{gclj: "M16", azxs: "径向"}]`
- 右段: 2行 → `[{lcfw: "低压"}, {lcfw: "高压"}]`
**笛卡尔积过程**:
```mermaid
flowchart LR
Left[左段: 1行<br/>gclj=M16, azxs=径向] --> Combine
Right[右段: 2行<br/>lcfw=低压, lcfw=高压] --> Combine
Combine[笛卡尔积 1×2] --> Row1[行1:<br/>gclj=M16<br/>azxs=径向<br/>lcfw=低压]
Combine --> Row2[行2:<br/>gclj=M16<br/>azxs=径向<br/>lcfw=高压]
```
**最终结果**:
```javascript
Collection {
[1] Dictionary {gclj: "M16", azxs: "径向", lcfw: "低压"},
[2] Dictionary {gclj: "M16", azxs: "径向", lcfw: "高压"}
}
```
### 步骤 7: 结果验证
```vba
Assert_Equal col.count, 2, "PP06_Count_After_Preprocessing" ' ✓ 通过
Assert_Equal row("gclj"), "M16", "PP06_gclj_Value" ' ✓ 通过
Assert_Equal row("azxs"), "径向", "PP06_azxs_Mapped_Value" ' ✓ 通过
Assert_Equal row("lcfw"), "低压", "PP06_lcfw_Mapped_Value" ' ✓ 通过
```
---
## 关键数据结构
### 1. 映射表 Dictionary
```vba
' azxs 映射表
g_AzxsMapping: Scripting.Dictionary
Key: "A0" → Value: "径向"
Key: "AT" → Value: "径向"
Key: "AH" → Value: "径向"
Key: "B0" → Value: "下轴向"
...
' lcfw 映射表
g_LcfwMapping: Scripting.Dictionary
Key: "M01" → Value: "低压"
Key: "M15" → Value: "高压"
...
```
### 2. 原子解析结果
```vba
' ParseAtom 返回的 Dictionary
ParseAtom("azxs=A0") → Dictionary {
"key": "azxs",
"value": "A0",
"operator": "="
}
' ProcessAtom 处理后
ProcessAtom("azxs=A0") → "azxs=径向"
```
### 3. Collection 数据流
```mermaid
graph LR
A[SplitTopLevel OR] --> B[Collection: 2个元素]
B --> C["Element 1: azxs=A0"]
B --> D["Element 2: azxs=AT"]
C --> E[ProcessAndSegment]
D --> F[ProcessAndSegment]
E --> G["azxs=径向"]
F --> H["azxs=径向"]
G --> I[MergeDuplicateORs]
H --> I
I --> J[Collection: 1个元素<br/>azxs=径向]
```
### 4. 最终解析结果
```vba
' M03_Logic.ParseRule 返回的 Collection
Collection {
[1] Dictionary {
"gclj": "M16",
"azxs": "径向",
"lcfw": "低压"
},
[2] Dictionary {
"gclj": "M16",
"azxs": "径向",
"lcfw": "高压"
}
}
```
---
## 映射表说明
### azxs (安装形式) 映射规则
| 原始值 | 对应值 | 说明 |
|--------|--------|------|
| A0, AT, AH | 径向 | 径向安装 |
| B0, BT, BZ, BH | 下轴向 | 下轴向安装 |
| Z0, ZT, ZZ, ZH | 中轴向 | 中轴向安装 |
**测试用例**: `azxs=A0 OR azxs=AT`
- A0 → 径向
- AT → 径向
- 两个映射结果相同 → OR 去重 → `azxs=径向`
### lcfw (量程范围) 映射规则
| 原始值 | 对应值 | 说明 |
|--------|--------|------|
| M01-M11 | 低压 | 低压量程 |
| M12-M16 | 高压 | 高压量程 |
**测试用例**: `lcfw=M01 OR lcfw=M15`
- M01 → 低压
- M15 → 高压
- 两个映射结果不同 → OR 保留 → `lcfw=低压 OR lcfw=高压`
---
## 关键函数说明
### 1. SplitTopLevel()
**功能**: 顶层分割,尊重括号嵌套
**示例**:
```
输入: "A AND (B OR C) AND D"
分割符: " AND "
输出: ["A", "(B OR C)", "D"]
```
**算法**:
- 遍历字符串,跟踪 `bracketLevel`
- 只在 `bracketLevel = 0` 时匹配分隔符
### 2. ProcessAtom()
**功能**: 处理单个原子,应用值映射
**流程**:
```mermaid
flowchart TD
Input[输入: azxs=A0] --> Parse[ParseAtom]
Parse --> Dict[Dictionary: key=azxs, value=A0, operator==]
Dict --> CheckKey{检查key}
CheckKey -->|azxs| QueryAz[g_AzxsMapping.Exists]
CheckKey -->|lcfw| QueryLc[g_LcfwMapping.Exists]
CheckKey -->|其他| Keep[保持原值]
QueryAz --> FoundAz{找到?}
FoundAz -->|是| ReplaceAz[替换为映射值]
FoundAz -->|否| Keep
QueryLc --> FoundLc{找到?}
FoundLc -->|是| ReplaceLc[替换为映射值]
FoundLc -->|否| Keep
ReplaceAz --> Rebuild[重建: key+operator+value]
ReplaceLc --> Rebuild
Keep --> Rebuild
Rebuild --> Output[输出: azxs=径向]
```
### 3. SimplifyIfAllSame()
**功能**: 检查所有 OR 分段是否相同,相同则去重
**示例**:
```
输入: "azxs=径向 OR azxs=径向"
分段: ["azxs=径向", "azxs=径向"]
检查: 两段相同
输出: "azxs=径向"
```
### 4. HasTopLevelOperator()
**功能**: 检查字符串是否有顶层操作符
**示例**:
```
输入: "lcfw=低压 OR lcfw=高压"
检查: " OR " 在 bracketLevel=0 时出现
输出: True (需要括号)
```
---
## 测试覆盖的场景
| 场景 | 输入 | 预期输出 | 测试点 |
|------|------|----------|--------|
| 值映射 | azxs=A0 | azxs=径向 | ✓ azxs映射正确 |
| OR去重 | azxs=A0 OR azxs=AT | azxs=径向 | ✓ 相同映射值去重 |
| 括号保留 | (lcfw=M01 OR lcfw=M15) | (lcfw=低压 OR lcfw=高压) | ✓ 不同映射值保留括号 |
| 复杂表达式 | gclj=M16 AND (azxs=A0 OR azxs=AT) AND (...) | 完整表达式 | ✓ 多个嵌套括号处理 |
| 解析集成 | 预处理结果 | 2行数据 | ✓ 与M03_Logic集成 |
---
## 常见问题
### Q1: 为什么第一个括号去掉了,第二个括号保留了?
**A**:
- 第一个括号 `(azxs=A0 OR azxs=AT)``azxs=径向`
- 处理后是单个原子,无顶层操作符 → 不需要括号
- 第二个括号 `(lcfw=M01 OR lcfw=M15)``lcfw=低压 OR lcfw=高压`
- 处理后仍有顶层 OR → 需要括号保持逻辑结构
### Q2: 为什么最终生成2行而不是4行
**A**:
```
原始: (azxs=A0 OR azxs=AT) AND (lcfw=M01 OR lcfw=M15)
理论上: 2 × 2 = 4行
预处理后: azxs=径向 AND (lcfw=低压 OR lcfw=高压)
实际: 1 × 2 = 2行
原因: 第一个OR的两个值映射相同去重后变为1个值
```
### Q3: 如果映射值不同会怎样?
**A**:
```
输入: (azxs=A0 OR azxs=B0)
映射: A0→径向, B0→下轴向
输出: (azxs=径向 OR azxs=下轴向)
结果: 保留括号生成2行
```
---
## 总结
Test_PP_06_FullIntegration 测试验证了预处理模块的完整功能:
1.**值映射**: azxs 和 lcfw 的值正确映射
2.**OR去重**: 相同映射值的OR条件正确合并
3.**括号处理**: 根据处理后内容的复杂度智能决定是否保留括号
4.**逻辑集成**: 预处理结果能被M03_Logic正确解析
5.**结果正确**: 最终生成正确的行数和数据
该测试确保了预处理模块在实际使用中的正确性和可靠性。