如何在 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 20 或 123K 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
我有一道数学题:这五个字符串是同一个对象的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 20 或 123K 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。(K)
- 第二个捕获组捕获文字“K”。(\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