Excel VBA - Loop through cells and change capitalisation based on length

neodjandre

Well-known Member
Joined
Nov 29, 2006
Messages
950
Office Version
  1. 2019
Platform
  1. Windows
I am currently using this procedure which basically changes the capitalisation for all cells in a column and it works fine.

VBA Code:
Sub sanitise_data()

x_import.Activate

 With x_import.Range("A1", Cells(Rows.Count, "A").End(xlUp))
        .value = Evaluate("INDEX(Proper(" & .Address(External:=True) & "),)")
    End With
    
End Sub

The data is all in caps:

RUGBY UNION
WTA TOUR 500
WTA TOUR 1000
PGA TOUR CHAMPIONS
ATP 250
ATP 500
PGA TOUR
EIHL
EIHL
PREMIER LEAGUE
AEW
NHL
EUROPA LEAGUE
NHL
NHL
NBA
NHL
NHL
NBA
HARLEM GLOBETROTTERS 2022 SPREAD GAME TOUR

I am looking to add another loop to change back certain words to all CAPS such as EIHL, WTA,NHL,NBA etc.. which I can define in a VBA array perhaps. The function should be smart enough to analyse each word in each cell I presume.

much appreciate your help.
 

Excel Facts

Fastest way to copy a worksheet?
Hold down the Ctrl key while dragging tab for Sheet1 to the right. Excel will make a copy of the worksheet.
I made a no-VBA version since this wasn't getting a lot of traction out there.

MrExcelPlayground7.xlsx
ABCD
1RUGBY UNIONRugby UnionEIHL
2WTA TOUR 500WTA Tour 500WTA
3WTA TOUR 1000WTA Tour 1000NHL
4PGA TOUR CHAMPIONSPGA Tour ChampionsNBA
5ATP 250ATP 250AEW
6ATP 500ATP 500PGA
7PGA TOURPGA TourATP
8EIHLEIHL
9EIHLEIHL
10PREMIER LEAGUEPremier League
11AEWAEW
12NHLNHL
13EUROPA LEAGUEEuropa League
14NHLNHL
15NHLNHL
16NBANBA
17NHLNHL
18NHLNHL
19NBANBA
20HARLEM GLOBETROTTERS 2022 SPREAD GAME TOURHarlem Globetrotters 2022 Spread Game Tour
Sheet11
Cell Formulas
RangeFormula
B1:B20B1=TEXTJOIN(" ",TRUE,IF(ISNA(VLOOKUP(FILTERXML("<x><y>"&SUBSTITUTE(A1," ","</y><y>")&"</y></x>","//y"),D:D,1,FALSE)),PROPER(FILTERXML("<x><y>"&SUBSTITUTE(A1," ","</y><y>")&"</y></x>","//y")),FILTERXML("<x><y>"&SUBSTITUTE(A1," ","</y><y>")&"</y></x>","//y")))
 
Upvote 0
Hi to all.
Here is what I came up with:
VBA Code:
Option Explicit
Sub sanitise_data()
    Dim x_import As Worksheet
    Dim myArray As Variant
    Dim myCells As Long
    Dim x      As Long
    Dim first  As Long
    Dim intPos As Integer
    Set x_import = Sheets("Sheet1")               '<- change sheet name as needed
    x_import.Activate
    With Range("A1", Cells(Rows.Count, "A").End(xlUp))
        .Value = Evaluate("INDEX(Proper(" & .Address(External:=True) & "),)")
    End With
    myArray = Array("EIHL", "WTA", "NHL", "NBA")  '<- add items as needed
    For myCells = 1 To Range("A" & Rows.Count).End(xlUp).Row
        first = 1
        For x = LBound(myArray) To UBound(myArray)
            intPos = InStr(first, Range("A" & myCells), myArray(x), vbTextCompare)   'search item in cell
            If intPos > 0 Then
                Do
                    Range("A" & myCells) = Left(Range("A" & myCells), intPos - 1) & UCase(myArray(x)) & _
                              Mid(Range("A" & myCells), intPos + Len(myArray(x)), Len(Range("A" & myCells)) - intPos + Len(myArray(x)))
                    first = intPos + Len(myArray(x))
                    intPos = InStr(first, Range("A" & myCells), myArray(x), vbTextCompare)
                Loop While intPos > 0             'loop for repeated item in cell
            End If
        Next x
    Next myCells
    MsgBox "Done!"
End Sub
 
Last edited:
Upvote 0
Some general code comments first. Since you are activating** x_import
- there is no need to prefix Range("A1") with x_import
- there is no need for the evaluate address to be External
- I'm not sure why you have the INDEX in your evaluate line as I can't see that it is needed

** Generally there is no need to activate sheets to work with them. However, when using Evaluate it can be a good idea since the (often very long) External address required may possibly cause some other issues.

Anyway, this would be my changes/additions to your code.

VBA Code:
Dim a As Variant, aWords As Variant
Dim i As Long, j As Long
Dim UCaseWords As String

UCaseWords = ",EIHL,WTA,NHL,NBA," '<- Add more as required
x_import.Activate
With Range("A1", Cells(Rows.Count, "A").End(xlUp))
   .Value = Evaluate("Proper(" & .Address & ")")
   a = .Value
   For i = 1 To UBound(a)
    aWords = Split(a(i, 1))
    For j = 0 To UBound(aWords)
      If InStr(1, UCaseWords, "," & aWords(j) & ",", 1) > 0 Then aWords(j) = UCase(aWords(j))
    Next j
    a(i, 1) = Join(aWords)
   Next i
   .Value = a
End With
 
Upvote 0
I came up with this:

VBA Code:
Sub sanitise_data(sh As Worksheet, col As String)
Dim cell As Range
Dim rng As Range
Dim data As Variant
Dim i As Long

sh.Activate

'Convert Data to Proper Case
With sh
    Set rng = Range(col & "1", Cells(Rows.Count, col).End(xlUp))
    data = .Evaluate("INDEX(Proper(" & rng.Address & "),)")
End With

'Capitalise Exceptions
For i = 1 To UBound(data)
    If IsCap(data(i, 1)) Then data(i, 1) = UCase(data(i, 1))
Next i

rng.Offset(, 0) = data
End Sub

Function IsCap(ByVal s) As Boolean
Const Delim As String = ","
Dim Caps As Variant
    Caps = Split("Eihl,Wta,Nhl,Nba,Nfl", Delim)
IsCap = UBound(Filter(Caps, Split(s & " ")(0))) > -1
End Function

But it's a bit buggy when it comes to things like "Men'S" and "Women'S" and also for some reason TOUR stays capitalised even if its not in the exception list - will test your code now
 
Upvote 0
Some general code comments first. Since you are activating** x_import
- there is no need to prefix Range("A1") with x_import
- there is no need for the evaluate address to be External
- I'm not sure why you have the INDEX in your evaluate line as I can't see that it is needed

** Generally there is no need to activate sheets to work with them. However, when using Evaluate it can be a good idea since the (often very long) External address required may possibly cause some other issues.

Anyway, this would be my changes/additions to your code.

VBA Code:
Dim a As Variant, aWords As Variant
Dim i As Long, j As Long
Dim UCaseWords As String

UCaseWords = ",EIHL,WTA,NHL,NBA," '<- Add more as required
x_import.Activate
With Range("A1", Cells(Rows.Count, "A").End(xlUp))
   .Value = Evaluate("Proper(" & .Address & ")")
   a = .Value
   For i = 1 To UBound(a)
    aWords = Split(a(i, 1))
    For j = 0 To UBound(aWords)
      If InStr(1, UCaseWords, "," & aWords(j) & ",", 1) > 0 Then aWords(j) = UCase(aWords(j))
    Next j
    a(i, 1) = Join(aWords)
   Next i
   .Value = a
End With

Peter I think your code is better to use. but it has the same problem with Men'S and Women'S
 
Upvote 0
I just ended up adding this at the end to fix the apostrophe bug - in case someone else needs to refer to this.

VBA Code:
    .Replace What:="'S", Replacement:="'s", LookAt:=xlPart, _
        SearchOrder:=xlByRows, MatchCase:=True, SearchFormat:=False, _
        ReplaceFormat:=False
 
Upvote 0
also for some reason TOUR stays capitalised even if its not in the exception list
The word "tour" is not the problem. The problem is that the logic of your code is that if the first word in the cell is in the exception list then it capitalises the whole cell text.
See the coloured cells below which is your code (I adjusted the results offset to ,1) and produces all capitals if the first word is in the list (amber) but "tour" (& everything else) is fine when the first word is not in the list (green).

Also note your code's dealing with rows 15 & 16 (blue), if it is possible to have data like that.

As I mentioned before, INDEX does nothing in your "Evaluate" line other than add extra processing so you might as well get rid of it.

You could try this code that addresses all the above issues and also deals with the 'S on the way through. Results are offset ,2 in my code.

VBA Code:
Sub sanitise_data_PSSs_1(sh As Worksheet, col As String)
  Dim a As Variant, aWords As Variant
  Dim i As Long, j As Long
  Dim UCaseWords As String
  
  UCaseWords = ",Eihl,Wta,Nhl,Nba,Nfl," '<- Add more as required
  sh.Activate
  With Range("A1", Cells(Rows.Count, "A").End(xlUp))
     a = Evaluate("substitute(proper(substitute(" & .Address & ",""'S"",""z'z"")),""z'Z"",""'s"")")
     For i = 1 To UBound(a)
      aWords = Split(a(i, 1))
      For j = 0 To UBound(aWords)
        If InStr(1, UCaseWords, "," & aWords(j) & ",", 1) > 0 Then aWords(j) = UCase(aWords(j))
      Next j
      a(i, 1) = Join(aWords)
     Next i
     .Offset(, 2).Value = a
  End With
End Sub

neodjandre.xlsm
ABC
1RUGBY UNIONRugby UnionRugby Union
2WTA TOUR 500WTA TOUR 500WTA Tour 500
3PGA TOUR CHAMPIONSPga Tour ChampionsPga Tour Champions
4ATP 250Atp 250Atp 250
5PGA TOURPga TourPga Tour
6EIHLEIHLEIHL
7PREMIER LEAGUEPremier LeaguePremier League
8AEWAewAew
9NHLNHLNHL
10EUROPA LEAGUEEuropa LeagueEuropa League
11NHLNHLNHL
12NBANBANBA
13NHL HARLEM GLOBETROTTERS 2022 SPREAD GAME TOURNHL HARLEM GLOBETROTTERS 2022 SPREAD GAME TOURNHL Harlem Globetrotters 2022 Spread Game Tour
14MEN'S COMPMen's CompMen's Comp
15O'CONNOR LEAGUEO'connor LeagueO'Connor League
16PREMIER NHL LEAGUEPremier Nhl LeaguePremier NHL League
Sheet3
 
Upvote 0

Forum statistics

Threads
1,214,653
Messages
6,120,751
Members
448,989
Latest member
mariah3

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top