' ============================================================================== ' 模块: M05_PreProcessor ' 职责: 预处理条件表达式,支持不同类别的差异化处理 ' - "接头"类别: 完整预处理(azxs映射 + lcfw映射 + OR合并 + 括号简化) ' - "部件"类别: 部分预处理(azxs映射 + OR合并 + 括号简化,不处理lcfw) ' - 其他类别: 不进行预处理 ' 使用正则表达式实现高效的值映射和OR条件合并 ' ============================================================================== 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 ' ------------------------------------------------------------------------------ ' 主入口:预处理条件表达式 ' 支持的类别: ' - "接头": 完整预处理(azxs映射 + lcfw映射 + OR合并 + 括号简化) ' - "部件": 部分预处理(azxs映射 + OR合并 + 括号简化,不处理lcfw) ' - 其他: 不进行预处理 ' ------------------------------------------------------------------------------ Public Function PreprocessCondition( _ ByVal strCondition As String, _ ByVal strCategory As String, _ ByVal rowIdx As Long _ ) As String If Not g_IsInitialized Then PreprocessCondition = strCondition Exit Function End If ' 根据类别选择处理策略 If strCategory = "接头" Then ' 完整预处理:azxs + lcfw + OR合并 + 括号简化 PreprocessCondition = ApplyPreprocessing(strCondition, rowIdx) ElseIf strCategory = "部件" Then ' 部分预处理:azxs + OR合并 + 括号简化(不处理 lcfw) PreprocessCondition = ApplyPreprocessingWithoutLcfw(strCondition, rowIdx) Else ' 其他类别:不处理 PreprocessCondition = strCondition End If 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 ' 步骤1: 应用 azxs 映射 ' 正则模式: (azxs)( *=|!= *)([a-zA-Z0-9]{2}) ' 捕获组: key, operator, value (2位字母数字) strCondition = ApplyRegexMapping( _ strCondition, _ "(azxs)( *=|!= *)([a-zA-Z0-9]{2})", _ g_AzxsMapping, _ rowIdx, _ "azxs" _ ) ' 步骤2: 应用 lcfw 映射 ' 正则模式: (lcfw)( *=|!= *)([a-zA-Z]\d{1,3})(?=[ \(\)]?) ' 捕获组: key, operator, value (字母+1-3位数字) ' 使用正向先行断言 (?=...) 确保不消耗后续字符 strCondition = ApplyRegexMapping( _ strCondition, _ "(lcfw)( *=|!= *)([a-zA-Z]\d{1,3})(?=[ \(\)]?)", _ g_LcfwMapping, _ rowIdx, _ "lcfw" _ ) ' 步骤3: 递归处理嵌套括号内的表达式(合并OR,简化括号) strCondition = ProcessNestedExpressions(strCondition, rowIdx) ' 步骤4: 合并顶层重复的OR条件 strCondition = MergeDuplicateORConditions(strCondition) ' 步骤5: 简化不必要的括号 strCondition = SimplifyParentheses(strCondition) ApplyPreprocessing = strCondition End Function ' ------------------------------------------------------------------------------ ' 应用预处理(不含 lcfw 映射):用于"部件"类别 ' 执行步骤:azxs 映射 → 嵌套表达式处理 → OR合并 → 括号简化 ' ------------------------------------------------------------------------------ Private Function ApplyPreprocessingWithoutLcfw( _ ByVal strCondition As String, _ ByVal rowIdx As Long _ ) As String ' 步骤1: 应用 azxs 映射 strCondition = ApplyRegexMapping( _ strCondition, _ "(azxs)( *=|!= *)([a-zA-Z0-9]{2})", _ g_AzxsMapping, _ rowIdx, _ "azxs" _ ) ' 步骤2: 递归处理嵌套括号内的表达式(合并OR,简化括号) strCondition = ProcessNestedExpressions(strCondition, rowIdx) ' 步骤3: 合并顶层重复的OR条件 strCondition = MergeDuplicateORConditions(strCondition) ' 步骤4: 简化不必要的括号 strCondition = SimplifyParentheses(strCondition) ApplyPreprocessingWithoutLcfw = strCondition End Function ' ------------------------------------------------------------------------------ ' 递归处理嵌套表达式:先预处理括号内的内容,再进行OR合并 ' ------------------------------------------------------------------------------ Private Function ProcessNestedExpressions( _ 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 = ProcessNestedExpressions(bracketContent, rowIdx) ' 对处理后的内容进行OR合并和简化 processedContent = MergeDuplicateORConditions(processedContent) processedContent = SimplifyIfAllSame(processedContent) ' 重新组装:决定是否需要保留括号 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 ProcessNestedExpressions = result End Function ' ------------------------------------------------------------------------------ ' 使用正则表达式应用值映射 ' ------------------------------------------------------------------------------ Private Function ApplyRegexMapping( _ ByVal strCondition As String, _ ByVal pattern As String, _ ByVal mapping As Object, _ ByVal rowIdx As Long, _ ByVal keyName As String _ ) As String ' 创建 RegExp 对象 (Late Binding) Dim regex As Object Set regex = CreateObject("VBScript.RegExp") With regex .Global = True ' 全局匹配 .IgnoreCase = True ' 不区分大小写 .Pattern = pattern End With ' 执行匹配 Dim matches As Object Set matches = regex.Execute(strCondition) ' 如果没有匹配,直接返回原字符串 If matches.count = 0 Then ApplyRegexMapping = strCondition Exit Function End If ' 执行替换:从后向前替换,避免位置偏移问题 Dim result As String result = strCondition Dim i As Long For i = matches.count - 1 To 0 Step -1 Dim match As Object Set match = matches(i) Dim originalValue As String originalValue = match.SubMatches(2) ' 查询映射表 If mapping.Exists(originalValue) Then Dim mappedValue As String Dim replacementStr As String mappedValue = mapping(originalValue) ' 构建替换字符串,保留原始格式(空格等) replacementStr = match.SubMatches(0) & match.SubMatches(1) & mappedValue ' 使用正则对象的 Replace 方法进行精确替换 ' 创建精确匹配当前 match 的模式 Dim exactPattern As String exactPattern = EscapeForRegex(match.Value) Dim exactRegex As Object Set exactRegex = CreateObject("VBScript.RegExp") With exactRegex .Global = False ' 只替换第一个匹配(从后向前,每次只处理一个) .IgnoreCase = True .Pattern = exactPattern End With result = exactRegex.Replace(result, replacementStr) Else ' 记录警告 g_Logger.Record rowIdx, "M05.PreProcessor", "Mapping Warning", _ "Value not found in mapping table: " & keyName & "=" & originalValue, match.Value End If Next i ApplyRegexMapping = result End Function ' ------------------------------------------------------------------------------ ' 转义字符串用于正则表达式(转义特殊字符) ' ------------------------------------------------------------------------------ Private Function EscapeForRegex(ByVal str As String) As String ' 转义正则表达式特殊字符: . \ + * ? [ ] { } ( ) ^ $ | Dim result As String result = str ' 必须按顺序转义 \ 先转义 result = Replace(result, "\", "\\") result = Replace(result, ".", "\.") result = Replace(result, "+", "\+") result = Replace(result, "*", "\*") result = Replace(result, "?", "\?") result = Replace(result, "[", "\[") result = Replace(result, "]", "\]") result = Replace(result, "{", "\{") result = Replace(result, "}", "\}") result = Replace(result, "(", "\(") result = Replace(result, ")", "\)") result = Replace(result, "^", "\^") result = Replace(result, "$", "\$") result = Replace(result, "|", "\|") EscapeForRegex = result End Function ' ------------------------------------------------------------------------------ ' 合并重复的OR条件 ' ------------------------------------------------------------------------------ Private Function MergeDuplicateORConditions( _ ByVal strCondition As String _ ) As String ' 按顶层OR分割 Dim orSegments As Collection Set orSegments = SplitTopLevel(strCondition, " OR ") ' 如果只有一个分段或没有OR,直接返回 If orSegments.count <= 1 Then MergeDuplicateORConditions = strCondition Exit Function End If ' 使用Dictionary去重(标准化后比较) Dim uniqueSegments As Object Set uniqueSegments = CreateObject("Scripting.Dictionary") Dim segment As Variant For Each segment In orSegments 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 MergeDuplicateORConditions = result End Function ' ------------------------------------------------------------------------------ ' 简化不必要的括号 ' ------------------------------------------------------------------------------ Private Function SimplifyParentheses( _ ByVal strCondition As String _ ) As String strCondition = Trim(strCondition) ' 如果没有外层括号,直接返回 If Left(strCondition, 1) <> "(" Or Right(strCondition, 1) <> ")" Then SimplifyParentheses = strCondition Exit Function End If ' 去掉外层括号,检查内容 Dim innerContent As String innerContent = Mid(strCondition, 2, Len(strCondition) - 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 SimplifyParentheses = innerContent Exit Function End If ' 如果有OR操作符但所有分段都相同,可以简化 If hasTopLevelOR And Not hasTopLevelAND Then Dim simplified As String simplified = SimplifyIfAllSame(innerContent) ' 如果简化后没有括号,返回简化结果 If Left(simplified, 1) <> "(" Then SimplifyParentheses = simplified Exit Function End If End If ' 保留括号 SimplifyParentheses = strCondition 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 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 ' ------------------------------------------------------------------------------ ' 顶层分割(尊重括号嵌套) ' ------------------------------------------------------------------------------ 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 ' ------------------------------------------------------------------------------ ' 标准化空白字符 ' ------------------------------------------------------------------------------ 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 ' ------------------------------------------------------------------------------ ' 测试辅助函数:获取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