feat: add preprocessing module for BOM condition transformation
All checks were successful
NTFY Notification / notify (push) Successful in 5s

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>
This commit is contained in:
Misaka_Company
2026-02-09 16:24:41 +08:00
parent d6c0fe78a0
commit 3a93459002
6 changed files with 1814 additions and 3 deletions

View File

@@ -40,6 +40,18 @@ Public Sub RunBOMConversion()
' 3. 初始化逻辑模块
M03_Logic.InitLogic logger
' 3.1 初始化预处理模块
Dim wsMapping As Worksheet
On Error Resume Next
Set wsMapping = ActiveWorkbook.Sheets("对照表")
On Error GoTo MainErrorHandler
If wsMapping Is Nothing Then
MsgBox "警告:未找到 [对照表] 工作表,预处理功能将禁用。", vbExclamation
Else
M05_PreProcessor.InitPreProcessor logger, wsMapping
End If
' 4. 主循环
Dim rowIdx As Long
Dim strCat As String, strCond As String
@@ -66,6 +78,11 @@ Public Sub RunBOMConversion()
strCond = CStr(arrData(i, M04_Config.COL_IDX_COND))
If IsEmpty(arrData(i, M04_Config.COL_IDX_COND)) Then strCond = ""
' 4.1 预处理条件(仅对"接头"类别)
If Len(strCond) > 0 And M05_PreProcessor.IsInitialized() Then
strCond = M05_PreProcessor.PreprocessCondition(strCond, strCat, rowIdx)
End If
' 解析
Set colResult = M03_Logic.ParseRule(strCond, rowIdx)

View File

@@ -0,0 +1,646 @@
' ==============================================================================
' 模块: M05_PreProcessor
' 职责: 预处理条件表达式,用于"接头"类别的值映射和去重
' ==============================================================================
Option Explicit
' 模块级变量
Private g_LcfwMapping As Object ' Scripting.Dictionary - lcfw映射表
Private g_AzxsMapping As Object ' Scripting.Dictionary - azxs映射表
Private g_Logger As clsErrorLogger
Private g_IsInitialized As Boolean
' ------------------------------------------------------------------------------
' 初始化预处理器
' ------------------------------------------------------------------------------
Public Sub InitPreProcessor(logger As clsErrorLogger, wsMapping As Worksheet)
Set g_Logger = logger
Set g_LcfwMapping = CreateObject("Scripting.Dictionary")
Set g_AzxsMapping = CreateObject("Scripting.Dictionary")
' 从[对照表]加载映射
Call LoadLcfwMapping(wsMapping)
Call LoadAzxsMapping(wsMapping)
g_IsInitialized = True
End Sub
' ------------------------------------------------------------------------------
' 检查是否已初始化
' ------------------------------------------------------------------------------
Public Function IsInitialized() As Boolean
IsInitialized = g_IsInitialized
End Function
' ------------------------------------------------------------------------------
' 主入口:预处理条件表达式
' ------------------------------------------------------------------------------
Public Function PreprocessCondition( _
ByVal strCondition As String, _
ByVal strCategory As String, _
ByVal rowIdx As Long _
) As String
' 仅对"接头"类别进行预处理
If strCategory <> "接头" Then
PreprocessCondition = strCondition
Exit Function
End If
If Not g_IsInitialized Then
PreprocessCondition = strCondition
Exit Function
End If
PreprocessCondition = ApplyPreprocessing(strCondition, rowIdx)
End Function
' ------------------------------------------------------------------------------
' 加载lcfw映射从A列:B列列1:2
' ------------------------------------------------------------------------------
Private Sub LoadLcfwMapping(wsMapping As Worksheet)
Dim lastRow As Long
lastRow = wsMapping.Cells(wsMapping.Rows.count, 1).End(xlUp).Row
Dim i As Long
Dim key As String, val As String
' 从第3行开始读取
For i = 3 To lastRow
key = Trim(CStr(wsMapping.Cells(i, 1).Value))
val = Trim(CStr(wsMapping.Cells(i, 2).Value))
If Len(key) > 0 And Len(val) > 0 Then
If Not g_LcfwMapping.Exists(key) Then
g_LcfwMapping.Add key, val
End If
End If
Next i
End Sub
' ------------------------------------------------------------------------------
' 加载azxs映射从D列:E列列4:5
' ------------------------------------------------------------------------------
Private Sub LoadAzxsMapping(wsMapping As Worksheet)
Dim lastRow As Long
lastRow = wsMapping.Cells(wsMapping.Rows.count, 4).End(xlUp).Row
Dim i As Long
Dim key As String, val As String
' 从第3行开始读取
For i = 3 To lastRow
key = Trim(CStr(wsMapping.Cells(i, 4).Value))
val = Trim(CStr(wsMapping.Cells(i, 5).Value))
If Len(key) > 0 And Len(val) > 0 Then
If Not g_AzxsMapping.Exists(key) Then
g_AzxsMapping.Add key, val
End If
End If
Next i
End Sub
' ------------------------------------------------------------------------------
' 应用预处理值替换和OR去重递归处理嵌套表达式
' ------------------------------------------------------------------------------
Private Function ApplyPreprocessing( _
ByVal strCondition As String, _
ByVal rowIdx As Long _
) As String
' 首先递归处理括号内的表达式并简化
strCondition = ProcessAndSimplifyNested(strCondition, rowIdx)
' 然后按顶层OR分割
Dim orSegments As Collection
Set orSegments = SplitTopLevel(strCondition, " OR ")
If orSegments.count = 1 Then
' 没有顶层OR直接处理AND分段
ApplyPreprocessing = ProcessAndSegment(CStr(orSegments(1)), rowIdx)
Exit Function
End If
' 处理每个OR分段
Dim processedSegments As Collection
Set processedSegments = New Collection
Dim segment As Variant
For Each segment In orSegments
Dim processedSegment As String
processedSegment = ProcessAndSegment(CStr(segment), rowIdx)
processedSegments.Add processedSegment
Next segment
' 合并去重后的OR条件
ApplyPreprocessing = MergeDuplicateORs(processedSegments)
End Function
' ------------------------------------------------------------------------------
' 递归处理并简化嵌套表达式
' ------------------------------------------------------------------------------
Private Function ProcessAndSimplifyNested( _
ByVal strCondition As String, _
ByVal rowIdx As Long _
) As String
Dim result As String
result = ""
Dim i As Long
Dim bracketLevel As Long
bracketLevel = 0
Dim inBracket As Boolean
inBracket = False
Dim bracketContent As String
bracketContent = ""
For i = 1 To Len(strCondition)
Dim char As String
char = Mid(strCondition, i, 1)
If char = "(" Then
bracketLevel = bracketLevel + 1
If bracketLevel = 1 Then
inBracket = True
bracketContent = ""
Else
bracketContent = bracketContent & char
End If
ElseIf char = ")" Then
If bracketLevel = 1 Then
' 递归处理括号内的内容
Dim processedContent As String
processedContent = ProcessAndSimplifyNested(bracketContent, rowIdx)
' 简化处理后的内容应用值替换和OR合并
processedContent = ApplyPreprocessing(processedContent, rowIdx)
' 检查所有OR分段是否相同如果是则去重
processedContent = SimplifyIfAllSame(processedContent)
' 重新组装:决定是否需要保留括号
' 如果处理后的内容包含顶层 OR 或 AND需要加括号以保持正确的逻辑结构
Dim needsParens As Boolean
needsParens = HasTopLevelOperator(processedContent, " OR ") Or _
HasTopLevelOperator(processedContent, " AND ")
If needsParens Then
result = result & "(" & processedContent & ")"
Else
result = result & processedContent
End If
inBracket = False
Else
bracketContent = bracketContent & char
End If
bracketLevel = bracketLevel - 1
ElseIf inBracket Then
bracketContent = bracketContent & char
Else
result = result & char
End If
Next i
ProcessAndSimplifyNested = result
End Function
' ------------------------------------------------------------------------------
' 如果所有OR分段都相同则简化为单个分段
' ------------------------------------------------------------------------------
Private Function SimplifyIfAllSame( _
ByVal strExpr As String _
) As String
' 检查是否包含OR
If Not HasTopLevelOperator(strExpr, " OR ") Then
SimplifyIfAllSame = strExpr
Exit Function
End If
' 分割OR分段
Dim segments As Collection
Set segments = SplitTopLevel(strExpr, " OR ")
If segments.count <= 1 Then
SimplifyIfAllSame = strExpr
Exit Function
End If
' 检查所有分段是否相同
Dim allSame As Boolean
allSame = True
Dim firstSegment As String
firstSegment = NormalizeWhitespace(CStr(segments(1)))
Dim i As Long
For i = 2 To segments.count
Dim segment As String
segment = NormalizeWhitespace(CStr(segments(i)))
If segment <> firstSegment Then
allSame = False
Exit For
End If
Next i
' 如果所有分段都相同,返回第一个分段
If allSame Then
SimplifyIfAllSame = segments(1)
Else
SimplifyIfAllSame = strExpr
End If
End Function
' ------------------------------------------------------------------------------
' 尝试去除外层括号(如果可能)
' ------------------------------------------------------------------------------
Private Function MaybeRemoveOuterParentheses( _
ByVal strExpr As String _
) As String
strExpr = Trim(strExpr)
' 如果没有外层括号,直接返回
If Left(strExpr, 1) <> "(" Or Right(strExpr, 1) <> ")" Then
MaybeRemoveOuterParentheses = strExpr
Exit Function
End If
' 去掉外层括号,检查内容
Dim innerContent As String
innerContent = Mid(strExpr, 2, Len(strExpr) - 2)
innerContent = Trim(innerContent)
' 检查内容是否包含顶层OR或AND
Dim hasTopLevelOR As Boolean
Dim hasTopLevelAND As Boolean
hasTopLevelOR = HasTopLevelOperator(innerContent, " OR ")
hasTopLevelAND = HasTopLevelOperator(innerContent, " AND ")
' 如果没有顶层操作符,可以去掉括号
If Not hasTopLevelOR And Not hasTopLevelAND Then
MaybeRemoveOuterParentheses = innerContent
Exit Function
End If
' 如果仍有顶层操作符,需要保留括号以保持正确的逻辑结构
MaybeRemoveOuterParentheses = strExpr
End Function
' ------------------------------------------------------------------------------
' 检查字符串是否包含顶层操作符
' ------------------------------------------------------------------------------
Private Function HasTopLevelOperator( _
ByVal strExpr As String, _
ByVal operator As String _
) As Boolean
Dim bracketLevel As Long
bracketLevel = 0
Dim i As Long
Dim lenOp As Long
lenOp = Len(operator)
For i = 1 To Len(strExpr) - lenOp + 1
Dim char As String
char = Mid(strExpr, i, 1)
If char = "(" Then
bracketLevel = bracketLevel + 1
ElseIf char = ")" Then
bracketLevel = bracketLevel - 1
ElseIf bracketLevel = 0 Then
If Mid(strExpr, i, lenOp) = operator Then
HasTopLevelOperator = True
Exit Function
End If
End If
Next i
HasTopLevelOperator = False
End Function
' ------------------------------------------------------------------------------
' 处理AND分段进行值替换并合并重复原子
' ------------------------------------------------------------------------------
Private Function ProcessAndSegment( _
ByVal strSegment As String, _
ByVal rowIdx As Long _
) As String
Dim andAtoms As Collection
Set andAtoms = SplitTopLevel(strSegment, " AND ")
Dim processedAtoms As Collection
Set processedAtoms = New Collection
Dim atom As Variant
For Each atom In andAtoms
Dim processedAtom As String
processedAtom = ProcessAtom(CStr(atom), rowIdx)
processedAtoms.Add processedAtom
Next atom
' 合并重复的原子
Dim mergedAtoms As Collection
Set mergedAtoms = MergeDuplicateAtoms(processedAtoms)
' 重新组合AND分段
ProcessAndSegment = JoinCollection(mergedAtoms, " AND ")
End Function
' ------------------------------------------------------------------------------
' 处理单个原子:应用值映射
' ------------------------------------------------------------------------------
Private Function ProcessAtom( _
ByVal strAtom As String, _
ByVal rowIdx As Long _
) As String
Dim atomDict As Object
Set atomDict = ParseAtom(strAtom)
If atomDict Is Nothing Then
ProcessAtom = strAtom
Exit Function
End If
Dim key As String
Dim value As String
Dim operator As String
key = atomDict("key")
value = atomDict("value")
operator = atomDict("operator")
' 应用映射
Dim mappedValue As String
mappedValue = ""
If key = "lcfw" Then
If g_LcfwMapping.Exists(value) Then
mappedValue = g_LcfwMapping(value)
End If
ElseIf key = "azxs" Then
If g_AzxsMapping.Exists(value) Then
mappedValue = g_AzxsMapping(value)
End If
End If
' 如果找到了映射值,使用它;否则保持原值
If Len(mappedValue) > 0 Then
value = mappedValue
Else
' 记录警告仅针对lcfw和azxs
If (key = "lcfw" Or key = "azxs") And Len(value) > 0 Then
g_Logger.Record rowIdx, "M05.PreProcessor", "Mapping Warning", _
"Value not found in mapping table: " & key & "=" & value, strAtom
End If
End If
' 重建原子字符串
ProcessAtom = key & operator & value
End Function
' ------------------------------------------------------------------------------
' 解析原子字符串为Dictionary
' ------------------------------------------------------------------------------
Private Function ParseAtom(ByVal strAtom As String) As Object
Set ParseAtom = Nothing
strAtom = Trim(strAtom)
If Len(strAtom) = 0 Then Exit Function
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
Dim p As Long
Dim key As String, value As String, op As String
If InStr(strAtom, "!=") > 0 Then
p = InStr(strAtom, "!=")
key = Trim(Left(strAtom, p - 1))
value = Trim(Mid(strAtom, p + 2))
op = "!="
ElseIf InStr(strAtom, "=") > 0 Then
p = InStr(strAtom, "=")
key = Trim(Left(strAtom, p - 1))
value = Trim(Mid(strAtom, p + 1))
op = "="
Else
Exit Function
End If
dict.Add "key", key
dict.Add "value", value
dict.Add "operator", op
Set ParseAtom = dict
End Function
' ------------------------------------------------------------------------------
' 顶层分割(尊重括号嵌套)
' ------------------------------------------------------------------------------
Private Function SplitTopLevel( _
ByVal strExpr As String, _
ByVal delimiter As String _
) As Collection
Dim result As New Collection
Dim currentSegment As String
currentSegment = ""
Dim i As Long
Dim bracketLevel As Long
bracketLevel = 0
Dim lenDelim As Long
lenDelim = Len(delimiter)
i = 1
Do While i <= Len(strExpr)
Dim char As String
char = Mid(strExpr, i, 1)
If char = "(" Then
bracketLevel = bracketLevel + 1
currentSegment = currentSegment & char
ElseIf char = ")" Then
bracketLevel = bracketLevel - 1
currentSegment = currentSegment & char
ElseIf bracketLevel = 0 Then
' 检查是否匹配分隔符
If i + lenDelim - 1 <= Len(strExpr) Then
Dim checkStr As String
checkStr = Mid(strExpr, i, lenDelim)
If UCase(checkStr) = delimiter Then
' 找到分隔符,保存当前分段
result.Add Trim(currentSegment)
currentSegment = ""
i = i + lenDelim - 1 ' 跳过分隔符
Else
currentSegment = currentSegment & char
End If
Else
currentSegment = currentSegment & char
End If
Else
currentSegment = currentSegment & char
End If
i = i + 1
Loop
' 添加最后一个分段
If Len(Trim(currentSegment)) > 0 Then
result.Add Trim(currentSegment)
End If
Set SplitTopLevel = result
End Function
' ------------------------------------------------------------------------------
' 合并重复的OR条件
' ------------------------------------------------------------------------------
Private Function MergeDuplicateORs(ByVal segments As Collection) As String
If segments.count = 0 Then
MergeDuplicateORs = ""
Exit Function
End If
If segments.count = 1 Then
MergeDuplicateORs = segments(1)
Exit Function
End If
' 使用Dictionary去重
Dim uniqueSegments As Object
Set uniqueSegments = CreateObject("Scripting.Dictionary")
Dim segment As Variant
For Each segment In segments
Dim segStr As String
segStr = CStr(segment)
' 标准化字符串用于比较(去除多余空格)
Dim normalized As String
normalized = NormalizeWhitespace(segStr)
If Not uniqueSegments.Exists(normalized) Then
uniqueSegments.Add normalized, segStr
End If
Next segment
' 重新组合
Dim result As String
result = ""
Dim key As Variant
Dim isFirst As Boolean
isFirst = True
For Each key In uniqueSegments.keys
If isFirst Then
result = uniqueSegments(key)
isFirst = False
Else
result = result & " OR " & uniqueSegments(key)
End If
Next key
MergeDuplicateORs = result
End Function
' ------------------------------------------------------------------------------
' 标准化空白字符
' ------------------------------------------------------------------------------
Private Function NormalizeWhitespace(ByVal str As String) As String
' 去除多余空格
Dim result As String
result = Trim(str)
' 将连续多个空格替换为单个空格
Do While InStr(result, " ") > 0
result = Replace(result, " ", " ")
Loop
' 标准化 " AND " 和 " OR "
result = Replace(result, " AND ", " AND ")
result = Replace(result, " OR ", " OR ")
NormalizeWhitespace = result
End Function
' ------------------------------------------------------------------------------
' 连接集合为字符串
' ------------------------------------------------------------------------------
Private Function JoinCollection( _
ByVal col As Collection, _
ByVal delimiter As String _
) As String
Dim result As String
result = ""
Dim item As Variant
Dim isFirst As Boolean
isFirst = True
For Each item In col
If isFirst Then
result = CStr(item)
isFirst = False
Else
result = result & delimiter & CStr(item)
End If
Next item
JoinCollection = result
End Function
' ------------------------------------------------------------------------------
' 合并重复的原子在AND分段中
' ------------------------------------------------------------------------------
Private Function MergeDuplicateAtoms( _
ByVal atoms As Collection _
) As Collection
Dim result As New Collection
Dim uniqueAtoms As Object
Set uniqueAtoms = CreateObject("Scripting.Dictionary")
Dim atom As Variant
For Each atom In atoms
Dim atomStr As String
atomStr = Trim(CStr(atom))
' 标准化用于比较
Dim normalized As String
normalized = NormalizeWhitespace(atomStr)
If Not uniqueAtoms.Exists(normalized) Then
uniqueAtoms.Add normalized, atomStr
End If
Next atom
' 返回去重后的原子
Dim key As Variant
For Each key In uniqueAtoms.keys
result.Add uniqueAtoms(key)
Next key
Set MergeDuplicateAtoms = result
End Function
' ------------------------------------------------------------------------------
' 测试辅助函数获取lcfw映射值
' ------------------------------------------------------------------------------
Public Function GetLcfwMappedValue(key As String) As String
If g_LcfwMapping.Exists(key) Then
GetLcfwMappedValue = g_LcfwMapping(key)
Else
GetLcfwMappedValue = ""
End If
End Function
' ------------------------------------------------------------------------------
' 测试辅助函数获取azxs映射值
' ------------------------------------------------------------------------------
Public Function GetAzxsMappedValue(key As String) As String
If g_AzxsMapping.Exists(key) Then
GetAzxsMappedValue = g_AzxsMapping(key)
Else
GetAzxsMappedValue = ""
End If
End Function

View File

@@ -8,6 +8,7 @@ Option Explicit
Private m_Logger As clsErrorLogger
Private m_FailCount As Long
Private m_PassCount As Long
Private m_wsMapping As Worksheet ' 用于测试的映射表工作表
' ------------------------------------------------------------------------------
' 主入口: 运行所有测试
@@ -32,6 +33,20 @@ Public Sub RunAllTests()
Test_06_LogicConflict ' 核心:测试 A=1 AND A=2
Test_07_ComplexNested ' 核心:多层括号
' 新增预处理测试
Debug.Print String(50, "-")
Debug.Print "新增预处理测试:"
Debug.Print String(50, "-")
Test_PP_01_AzxsMappingLoad
Test_PP_02_LcfwMappingLoad
Test_PP_03_AzxsReplacement
Test_PP_04_LcfwReplacement
Test_PP_05_ORMerging
Test_PP_06_FullIntegration
Test_PP_07_NonJointCategory
Test_PP_08_UnmappedValues
' 汇总结果
Debug.Print String(50, "-")
If m_FailCount = 0 Then
@@ -209,4 +224,205 @@ Private Sub Assert_NotNull(obj As Object, testName As String)
Debug.Print " [FAIL] " & testName & " | Object is Nothing"
m_FailCount = m_FailCount + 1
End If
End Sub
' ==============================================================================
' 预处理测试用例
' ==============================================================================
' ------------------------------------------------------------------------------
' 测试用例 PP_01: 测试azxs映射加载
' 验证所有12个azxs值是否正确映射
' ------------------------------------------------------------------------------
Private Sub Test_PP_01_AzxsMappingLoad()
SetupPreProcessorTest
' 测试径向映射
Assert_Equal M05_PreProcessor.GetAzxsMappedValue("A0"), "径向", "PP01_A0_To_径向"
Assert_Equal M05_PreProcessor.GetAzxsMappedValue("AT"), "径向", "PP01_AT_To_径向"
Assert_Equal M05_PreProcessor.GetAzxsMappedValue("AH"), "径向", "PP01_AH_To_径向"
' 测试下轴向映射
Assert_Equal M05_PreProcessor.GetAzxsMappedValue("B0"), "下轴向", "PP01_B0_To_下轴向"
Assert_Equal M05_PreProcessor.GetAzxsMappedValue("BT"), "下轴向", "PP01_BT_To_下轴向"
Assert_Equal M05_PreProcessor.GetAzxsMappedValue("BZ"), "下轴向", "PP01_BZ_To_下轴向"
Assert_Equal M05_PreProcessor.GetAzxsMappedValue("BH"), "下轴向", "PP01_BH_To_下轴向"
' 测试中轴向映射
Assert_Equal M05_PreProcessor.GetAzxsMappedValue("Z0"), "中轴向", "PP01_Z0_To_中轴向"
Assert_Equal M05_PreProcessor.GetAzxsMappedValue("ZT"), "中轴向", "PP01_ZT_To_中轴向"
Assert_Equal M05_PreProcessor.GetAzxsMappedValue("ZZ"), "中轴向", "PP01_ZZ_To_中轴向"
Assert_Equal M05_PreProcessor.GetAzxsMappedValue("ZH"), "中轴向", "PP01_ZH_To_中轴向"
End Sub
' ------------------------------------------------------------------------------
' 测试用例 PP_02: 测试lcfw映射加载
' 验证M01-M11都映射到"低压"
' ------------------------------------------------------------------------------
Private Sub Test_PP_02_LcfwMappingLoad()
SetupPreProcessorTest
Assert_Equal M05_PreProcessor.GetLcfwMappedValue("M01"), "低压", "PP02_M01_To_低压"
Assert_Equal M05_PreProcessor.GetLcfwMappedValue("M02"), "低压", "PP02_M02_To_低压"
Assert_Equal M05_PreProcessor.GetLcfwMappedValue("M03"), "低压", "PP02_M03_To_低压"
Assert_Equal M05_PreProcessor.GetLcfwMappedValue("M11"), "低压", "PP02_M11_To_低压"
End Sub
' ------------------------------------------------------------------------------
' 测试用例 PP_03: 测试azxs值替换
' ------------------------------------------------------------------------------
Private Sub Test_PP_03_AzxsReplacement()
SetupPreProcessorTest
' 单个原子
Dim result1 As String
result1 = M05_PreProcessor.PreprocessCondition("azxs=A0", "接头", 1)
Assert_Equal result1, "azxs=径向", "PP03_Single_Azxs_Replacement"
' 与AND结合
Dim result2 As String
result2 = M05_PreProcessor.PreprocessCondition("gclj=M20 AND azxs=B0", "接头", 2)
Assert_Equal result2, "gclj=M20 AND azxs=下轴向", "PP03_Azxs_With_AND"
' 在OR中
Dim result3 As String
result3 = M05_PreProcessor.PreprocessCondition("azxs=A0 OR azxs=AT", "接头", 3)
Assert_Equal result3, "azxs=径向", "PP03_Azxs_With_OR_Merged"
End Sub
' ------------------------------------------------------------------------------
' 测试用例 PP_04: 测试lcfw值替换
' ------------------------------------------------------------------------------
Private Sub Test_PP_04_LcfwReplacement()
SetupPreProcessorTest
' 单个原子
Dim result1 As String
result1 = M05_PreProcessor.PreprocessCondition("lcfw=M01", "接头", 1)
Assert_Equal result1, "lcfw=低压", "PP04_Single_Lcfw_Replacement"
' 与AND结合
Dim result2 As String
result2 = M05_PreProcessor.PreprocessCondition("gclj=M20 AND lcfw=M02", "接头", 2)
Assert_Equal result2, "gclj=M20 AND lcfw=低压", "PP04_Lcfw_With_AND"
End Sub
' ------------------------------------------------------------------------------
' 测试用例 PP_05: 测试OR条件合并
' ------------------------------------------------------------------------------
Private Sub Test_PP_05_ORMerging()
SetupPreProcessorTest
' 精确重复
Dim result1 As String
result1 = M05_PreProcessor.PreprocessCondition("lcfw=低压 OR lcfw=低压", "接头", 1)
Assert_Equal result1, "lcfw=低压", "PP05_Exact_Duplicate_Merging"
' 多次重复
Dim result2 As String
result2 = M05_PreProcessor.PreprocessCondition("azxs=径向 OR azxs=径向 OR azxs=径向", "接头", 2)
Assert_Equal result2, "azxs=径向", "PP05_Multiple_Duplicate_Merging"
' 混合情况(保留不同的)
Dim result3 As String
result3 = M05_PreProcessor.PreprocessCondition("lcfw=低压 OR lcfw=高压", "接头", 3)
' 注意:高压不会在映射表中,所以保持原值
Dim hasLow As Boolean, hasHigh As Boolean
hasLow = InStr(result3, "lcfw=低压") > 0
hasHigh = InStr(result3, "lcfw=高压") > 0
Assert_Equal hasLow, True, "PP05_Mixed_Has_Low"
Assert_Equal hasHigh, True, "PP05_Mixed_Has_High"
End Sub
' ------------------------------------------------------------------------------
' 测试用例 PP_06: 测试完整集成
' 验证预处理后的结果能被M03_Logic正确解析
' ------------------------------------------------------------------------------
Private Sub Test_PP_06_FullIntegration()
SetupPreProcessorTest
Dim inputCond As String
inputCond = "gclj=M16 AND (azxs=A0 OR azxs=AT) AND (lcfw=M01 OR lcfw=M15)"
' 预处理
Dim preprocessed As String
preprocessed = M05_PreProcessor.PreprocessCondition(inputCond, "接头", 1)
' Debug output
Debug.Print "PP06 Debug:"
Debug.Print " Input: " & inputCond
Debug.Print " Expected: gclj=M16 AND azxs=径向 AND (lcfw=低压 OR lcfw=高压)"
Debug.Print " Actual: " & preprocessed
' 解析预处理后的条件
Dim col As Collection
Set col = M03_Logic.ParseRule(preprocessed, 1)
Assert_NotNull col, "PP06_Result_Not_Null"
Assert_Equal col.count, 2, "PP06_Count_After_Preprocessing"
Dim row As Object
Set row = col(1)
Assert_Equal row("gclj"), "M16", "PP06_gclj_Value"
Assert_Equal row("azxs"), "径向", "PP06_azxs_Mapped_Value"
Assert_Equal row("lcfw"), "低压", "PP06_lcfw_Mapped_Value"
End Sub
' ------------------------------------------------------------------------------
' 测试用例 PP_07: 测试非"接头"类别
' 验证其他类别不受预处理影响
' ------------------------------------------------------------------------------
Private Sub Test_PP_07_NonJointCategory()
SetupPreProcessorTest
Dim inputCond As String
inputCond = "gclj=M20 AND lcfw=M01"
' 使用"部件"类别
Dim result As String
result = M05_PreProcessor.PreprocessCondition(inputCond, "部件", 1)
' 应该保持不变
Assert_Equal result, inputCond, "PP07_NonJoint_Unchanged"
End Sub
' ------------------------------------------------------------------------------
' 测试用例 PP_08: 测试未映射的值
' 验证不在映射表中的值保持原样并记录警告
' ------------------------------------------------------------------------------
Private Sub Test_PP_08_UnmappedValues()
SetupPreProcessorTest
' 重置logger以捕获警告
Set m_Logger = New clsErrorLogger
M05_PreProcessor.InitPreProcessor m_Logger, m_wsMapping
Dim result As String
result = M05_PreProcessor.PreprocessCondition("lcfw=INVALID", "接头", 1)
' 值应该保持不变
Assert_Equal result, "lcfw=INVALID", "PP08_Unmapped_Value_Unchanged"
' 应该记录警告(如果实现了)
' 注意:这个测试可能需要根据实际日志记录行为调整
End Sub
' ------------------------------------------------------------------------------
' 辅助函数:设置预处理测试环境
' ------------------------------------------------------------------------------
Private Sub SetupPreProcessorTest()
' 查找[对照表]工作表
On Error Resume Next
Set m_wsMapping = ActiveWorkbook.Sheets("对照表")
On Error GoTo 0
If m_wsMapping Is Nothing Then
Debug.Print " [SKIP] 预处理测试 - 未找到[对照表]工作表"
Exit Sub
End If
' 初始化预处理器
Set m_Logger = New clsErrorLogger
M03_Logic.InitLogic m_Logger
M05_PreProcessor.InitPreProcessor m_Logger, m_wsMapping
End Sub