How to change case of matching letter with a VBA regex Replace?

孤街醉人 提交于 2020-04-07 08:53:11

问题


I have a column of lists of codes like the following.

2.A.B, 1.C.D, A.21.C.D, 1.C.D.11.C.D
6.A.A.5.F.A, 2.B.C.H.1
8.ABC.B, A.B.C.D
12.E.A, 3.NO.T
A.3.B.C.x, 1.N.N.9.J.K

I want to find all instances of two single upper-case letters separated by a period, but only those that follow a number less than 6. I want to remove the period between the letters and convert the second letter to lower case. Desired output:

2.Ab, 1.Cd, A.21.C.D, 1.Cd.11.C.D
6.A.A.5.Fa, 2.Bc.H.1
8.ABC.B, A.B.C.D
12.E.A, 3.NO.T
A.3.Bc.x, 1.Nn.9.J.K

I have the following code in VBA.

Sub fixBlah()
Dim re As VBScript_RegExp_55.RegExp
Set re = New VBScript_RegExp_55.RegExp
re.Global = True
re.Pattern = "\b([1-5]\.[A-Z])\.([A-Z])\b"
For Each c In Selection.Cells
    c.Value = re.Replace("$1$2")
Next c
End Sub

This removes the period, but doesn't handle the lower-case requirement. I know in other flavors of regular expressions, I can use something like

re.Replace("$1\L$2\E")

but this does not have the desired effect in VBA. I tried googling for this functionality, but I wasn't able to find anything. Is there a way to do this with a simple re.Replace() statement in VBA?

If not, how would I go about achieving this otherwise? The pattern matching is complex enough that I don't even want to think about doing this without regular expressions.

[I have a solution I worked up, posted below, but I'm hoping someone can come up with something simpler.]


回答1:


Here is a workaround that uses the properties of each individual regex match to make the VBA Replace() function replace only the text from the match and nothing else.

Sub fixBlah2()
Dim re As VBScript_RegExp_55.RegExp, Matches As VBScript_RegExp_55.MatchCollection
Dim M As VBScript_RegExp_55.Match
Dim tmpChr As String, pre As String, i As Integer
Set re = New VBScript_RegExp_55.RegExp
re.Global = True
re.Pattern = "\b([1-5]\.[A-Z])\.([A-Z])\b"
For Each c In Selection.Cells
    'Count of number of replacements made. This is used to adjust M.FirstIndex
    '    so that it still matches correct substring even after substitutions.
    i = 0
    Set Matches = re.Execute(c.Value)
    For Each M In Matches
        tmpChr = LCase(M.SubMatches.Item(1))
        If M.FirstIndex > 0 Then
            pre = Left(c.Value, M.FirstIndex - i)
        Else
            pre = ""
        End If
        c.Value = pre & Replace(c.Value, M.Value, M.SubMatches.Item(0) & tmpChr, _ 
                  M.FirstIndex + 1 - i, 1)
        i = i + 1
    Next M
Next c
End Sub

For reasons I don't quite understand, if you specify a start index in Replace(), the output starts at that index as well, so the pre variable is used to capture the first part of the string that gets clipped off by the Replace function.




回答2:


So this question is old, but I do have another workaround. I use a double regex so to speak, where the first engine looks for the match as an execute, then I loop through each of those items and replace with a lowercase version. For example:

Sub fixBlah()
Dim re As VBScript_RegExp_55.RegExp
dim ToReplace as Object
Set re = New VBScript_RegExp_55.RegExp
for each c in Selection.Cells
with re      `enter code here`
  .Global = True
  .Pattern = "\b([1-5]\.[A-Z])\.([A-Z])\b"
  Set ToReplace = .execute(C.Value)
end with

 'This generates a list of items that match.  Now to lowercase them and replace
 Dim LcaseVersion as string
 Dim ItemCt as integer
 for itemct = 0 to ToReplace.count - 1
 LcaseVersion = lcase(ToReplace.item(itemct))
      with re      `enter code here`
  .Global = True
  .Pattern = ToReplace.item(itemct)  'This looks for that specific item and replaces it with the lowercase version
  c.value = .replace(C.Value, LCaseVersion)
end with
End Sub

I hope this helps!



来源:https://stackoverflow.com/questions/23116876/how-to-change-case-of-matching-letter-with-a-vba-regex-replace

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!