从文本字符串提取数字分组并分栏:VBA脚本优化需求
金额提取VBA函数优化方案
问题背景
现有脚本运行缓慢,无法处理小数点,且Mac环境下无法使用正则表达式。需要从杂乱数据中提取有效数值,规则如下:
- 移除标识类数字(如WM01、WM03、50m2)
- 可移除小于10的数字(示例中7.00保留,可按需调整)
原始数据集
$2900 + Slab ($550) + P/Prep ($350) + Xover ($500) $2600 + Pave Prep ($350) + Slab ($550) + Crossover ($500) $2900 + $350 P/Prep + $500 Xover 2800+Slab$480+PavePrep$315+ Pave Prep$7.00+XOver$450 $3350(inc prep up to 50m2)+Slab$650+Extra P/prep$224+Xover$450 WM02-3050 XO-450 PPEX-128 SS-650 WM01-2850 XO-450 SS-650 XO-450 PPEX-307.68 SS-650 WM03-3350 DRYLINE-0 XO-450 PPEX-126.08 SS-650 WM01-2850
期望输出
2900 550 350 500 2600 350 550 500 2900 350 500 2800 480 315 7 450 3350 650 224 450 3050 450 128 650 2850 450 650 450 307.68 3350 450 126.08 650 2850
现有NDigits函数代码
Function NDigits(ByVal SourceString As String, _ Optional ByVal NumberOfDigits As Long = 0, _ Optional ByVal TargetDelimiter As String = " ") As String Dim i As Long ' SourceString Character Counter Dim strDel As String ' Current Target String ' Check if SourceString is empty (""). Exit if. NDigits = "". If SourceString = "" Then Exit Function ' Loop through characters of SourceString. For i = 1 To Len(SourceString) ' Check if current character is not a digit (#), then replace with " ". If Not Mid(SourceString, i, 1) Like "#" Then _ Mid(SourceString, i, 1) = " " Next ' Note: While VBA's Trim function removes spaces before and after a string, ' Excel's Trim function additionally removes redundant spaces, i.e. ' doesn't 'allow' more than one space, between words. ' Remove all spaces from SourceString except single spaces between words. strDel = Application.WorksheetFunction.Trim(SourceString) ' Check if current TargetString is empty (""). Exit if. NDigits = "". If strDel = "" Then Exit Function ' Replace (Substitute) " " with TargetDelimiter if it is different than ' " " and is not a number (#). If TargetDelimiter <> " " And Not TargetDelimiter Like "#" Then strDel = WorksheetFunction.Substitute(strDel, " ", TargetDelimiter) End If ' Check if NumberOfDigits is greater than 0. If NumberOfDigits > 0 Then Dim vnt As Variant ' Number of Digits Array (NOD Array) Dim k As Long ' NOD Array Element Counter ' Write (Split) Digit Groups from Current Target String to NOD Array. vnt = Split(strDel, TargetDelimiter) ' Reset NOD Array Element Counter to -1, because NOD Array is 0-based. k = -1 ' Loop through elements (digit groups) of NOD Array. For i = 0 To UBound(vnt) ' Check if current element has number of characters (digits) ' equal to NumberOfDigits. If Len(vnt(i)) = NumberOfDigits Then ' Count NOD Array Element i.e. prepare for write. k = k + 1 ' Write i-th element of NOD Array to k-th element. ' Note: Data (Digit Groups) are possibly being overwritten. vnt(k) = vnt(i) End If Next ' Check if no Digit Group of size of NumberOfDigits was found. ' Exit if. NDigits = "". If k = -1 Then Exit Function ' Resize NOD Array to NOD Array Element Count, possibly smaller, ' due to fewer found Digit Groups with the size of NumberOfDigits. ReDim Preserve vnt(k) ' Join elements of NOD Array to Current Target String. strDel = Join(vnt, TargetDelimiter) End If ' Write Current Target String to NDigits. NDigits = strDel End Function
优化后的函数代码
Function ExtractValidNumbers(ByVal SourceString As String, _ Optional ByVal TargetDelimiter As String = " ") As String Dim i As Long Dim currentChar As String Dim validNumbers As Collection Dim numStr As String Dim numVal As Double Set validNumbers = New Collection ' 遍历字符串,提取包含小数点的数字片段 For i = 1 To Len(SourceString) currentChar = Mid(SourceString, i, 1) ' 保留数字和小数点,其他字符作为分隔符 If currentChar Like "#" Or currentChar = "." Then numStr = numStr & currentChar Else ' 处理当前累积的数字片段 If numStr <> "" Then If IsNumeric(numStr) Then numVal = CDbl(numStr) ' 保留≥10的数值,或示例中的7.00(按需调整) If numVal >= 10 Or numVal = 7 Then validNumbers.Add numStr End If End If numStr = "" End If End If Next i ' 处理字符串末尾的数字片段 If numStr <> "" Then If IsNumeric(numStr) Then numVal = CDbl(numStr) If numVal >= 10 Or numVal = 7 Then validNumbers.Add numStr End If End If End If ' 拼接结果 Dim resultArr() As String ReDim resultArr(1 To validNumbers.Count) For i = 1 To validNumbers.Count resultArr(i) = validNumbers(i) Next i ExtractValidNumbers = Join(resultArr, TargetDelimiter) Set validNumbers = Nothing End Function
优化说明
- 支持小数点处理:修改字符判断逻辑,保留数字和小数点,正确提取带小数的数值(如307.68、126.08)。
- 过滤小数值:添加数值判断,仅保留≥10的数值,若需保留特定小数值(如示例中的7)可单独指定条件。
- 提升运行效率:采用Collection收集有效数值,避免多次字符串替换操作,减少内存占用。
- 适配Mac环境:全程使用VBA原生逻辑,未依赖正则表达式,兼容Mac系统。
内容的提问来源于stack exchange,提问作者3Dguy
相关产品推荐
相关产品推荐

