如何在 Excel 或 Access 使用 VBA 中格式化带有数字和特殊字符的字符串?

How to format strings with numbers and special characters in Excel or Access using VBA?

我有一道数学题:这五个字符串是同一个对象的ID。由于这些差异,对象在我的 Access table/query 中出现了多次。虽然这些突变有很多,但我以这个为例

76 K 6-18
76 K 6-18(2)
0076 K 0006/ 2018
0076 K 0006/2018
76 K 6/18

VBA-代码看起来如何识别这些数字代表同一事物,因此使用“RegEx()”或“format()”或“replace( )"...但他们不仅要参考这个例子,还要参考那种。

这些和所有其他突变的共同因素始终如下:

1) includes "-", no zeros left of "-", just 18 an not 2018 (year) at the end. 2) is like the first but with (2) (which can be dropped). 3) includes "/", zeros left of "/", and 2018 as year at the end. 4) is like third, but without space after "/". 5) is like the first one, but with a "/" instead of "-".

字符始终是一个“K”!我想最好的方法是将所有 5 个字符串转换为 76 K 6 18 或者在其他情况下例如转换为 1 K 21 20123K 117 20。这可以用一个优雅的代码或公式实现吗?谢谢

正如@Vincent 所建议的,考虑使用自定义函数将所有不同的数据转换为一致的。根据您的描述,以下似乎有效:

Function fConvertFormula(strData As String) As String
    On Error GoTo E_Handle
    Dim astrData() As String
    strData = Replace(strData, "/", " ")
    strData = Replace(strData, "-", " ")
    strData = Replace(strData, "  ", " ")
    astrData = Split(strData, " ")
    If UBound(astrData) = 3 Then
        astrData(0) = CLng(astrData(0))
        astrData(2) = CLng(astrData(2))
        If InStr(astrData(3), "(") > 0 Then
            astrData(3) = Left(astrData(3), InStr(astrData(3), "(") - 1)
        End If
        If Len(astrData(3)) = 4 Then
            astrData(3) = Right(astrData(3), 2)
        End If
        fConvertFormula = Join(astrData, " ")
    End If
fExit:
    On Error Resume Next
    Exit Function
E_Handle:
    MsgBox Err.Description & vbCrLf & vbCrLf & "fConvertFormula", vbOKOnly + vbCritical, "Error: " & Err.Number
    Resume fExit
End Function

它首先用空格替换“字段”分隔符,然后替换双空格。然后它会从第一个和第三个元素中删除所有前导零,如果最后一个元素中有括号则删除该部分,最后转换为 2 位值,然后再加入所有备份。

你可能还有其他情况需要处理,所以我建议用原始数据和这个函数转换后的数据创建一个查询,看看它会抛出什么。

此函数根据您在问题中定义的规则统一给定的字符串:

Public Function UnifyValue(ByVal inputValue As String) As String
        '// Remove all from "(" on.
        inputValue = Split(inputValue, "(")(0)
        '// Replace / by blank
        inputValue = Replace(inputValue, "/", " ")
        '// Replace - by blank
        inputValue = Replace(inputValue, "-", " ")
        '// Replace double blanks by one blank
        inputValue = Replace(inputValue, "  ", " ")
        '// Split by blank
        Dim splittedInputValue() As String
        splittedInputValue = Split(inputValue, " ")
        '// Create the resulting string
        UnifyValue = CLng(splittedInputValue(0)) & _
                     " " & splittedInputValue(1) & _
                     " " & CLng(splittedInputValue(2)) & _
                     " " & Right(CLng(splittedInputValue(3)), 2)
End Function

它总是 returns 76 K 6 18 关于你的样本值。

这是一个使用相当复杂但直观的正则表达式的有趣替代方法:

^0*(\d+) (K) 0*(\d+)[-\/] ?\d{0,2}(\d\d)(?:\(\d+\))?$

网上看一个demo

  • ^ - 起始行锚点。
  • 0* - 0+ 零以捕获任何可能的前导零。
  • (\d+) - 第一个捕获组 1+ 数字,范围为 0-9。
  • - 一个 space 字符。
  • (K) - 第二个捕获组捕获文字“K”。
  • - 一个 space 字符。
  • (\d+) - 第 3 个捕获组 1+ 数字,范围为 0-9。
  • [-\/] - 连字符或正斜杠的字符 class。
  • ? - 一个可选的 space 字符。
  • \d{0,2} - 0-2 位数字,范围为 0-9。
  • (\d\d) - 第 4 个捕获组恰好包含两位数字。
  • (?:\(\d+\))? - 一个可选的非捕获组,在文字括号内包含 1 个以上的数字。
  • $ - 结束行锚点。

现在只需用 4 个捕获组替换整个字符串,中间有 spaces。


让我们在 VBA 中进行测试:

'A code-block to call the function.
Sub Test()

    Dim arr As Variant: arr = Array("76 K 6-18", "76 K 6-18(2)", "0076 K 0006/ 2018", "0076 K 0006/2018", "76 K 6/18")

    For x = LBound(arr) To UBound(arr)
        Debug.Print Transform(CStr(arr(x)))
    Next

End Sub

'The function that transform the input.
Function Transform(StrIn As String) As String

    With CreateObject("vbscript.regexp")
        .Global = True
        .Pattern = "^0*(\d+) (K) 0*(\d+)[-\/] ?\d{0,2}(\d\d)(?:\(\d+\))?$"
        Transform = .Replace(StrIn, "   ")
    End With

End Function

初始数组中的所有元素都将 Debug.Print "76 K 6 18"。

希望对您有所帮助,编码愉快!


编辑:如果你的目标只是检查你的字符串是否根据模式编译,模式本身可以缩短一点,你可以 return 布尔值代替:

'A code-block to call the function.
Sub Test()

    Dim arr As Variant: arr = Array("76 K 6-18", "76 K 6-18(2)", "0076 K 0006/ 2018", "0076 K 0006/2018", "76 K 6/18")

    For x = LBound(arr) To UBound(arr)
        Debug.Print Transform(CStr(arr(x)))
    Next

End Sub

'The function that checks the input.
Function Transform(StrIn As String) As Boolean

    With CreateObject("vbscript.regexp")
        .Global = True
        .Pattern = "^0*\d+ K 0*\d+[-\/] ?\d{2,4}(?:\(\d+\))?$"
        Transform = .Test(StrIn)
    End With

End Function