You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从文本字符串提取数字分组并分栏: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

优化说明

  1. 支持小数点处理:修改字符判断逻辑,保留数字和小数点,正确提取带小数的数值(如307.68、126.08)。
  2. 过滤小数值:添加数值判断,仅保留≥10的数值,若需保留特定小数值(如示例中的7)可单独指定条件。
  3. 提升运行效率:采用Collection收集有效数值,避免多次字符串替换操作,减少内存占用。
  4. 适配Mac环境:全程使用VBA原生逻辑,未依赖正则表达式,兼容Mac系统。

内容的提问来源于stack exchange,提问作者3Dguy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 16:44:55