A string contains certain characters only - vba

I am new to VBA and Syntax in VBA is not very friendly to me. I'm trying to validate a field which is string type. In that particular field, I want the string contains letters and comma and space only.
This is my current approach:
myArray = Array("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", " ", ",", "-", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z")
If Not IsInArray(erName.Text, myArray) Then
valid = False
erName.ForeColor = vbRed
End If
And the IsInArray function is like the following:
Public Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
Dim i
For i = LBound(arr) To UBound(arr)
If arr(i) = stringToBeFound Then
IsInArray = True
Exit Function
End If
Next i
IsInArray = False
End Function
But this is not a very efficient approach because I don't want to loop over the array for every character in the string. Is there a simple way to perform this validation? Any help is appreciated. Thank you.

RegEx solution
Function StringCheck(str)
Set objRegEx = New RegExp
With objRegEx
.IgnoreCase = True
.Global = False
.MultiLine = False
.Pattern = "[a-zA-Z, ]*" 'alphabets + comma + space
End With
Set objMatch = objRegEx.Execute(str)
If objMatch.Count = 1 Then
If Len(str)=Len(objMatch(0).Value) Then 'if len of string matches the regex find
StringCheck = True
Else
StringCheck = False
End If
Else
StringCheck = False
End If
End Function
MsgBox StringCheck("Pankaj Jaju") 'True
MsgBox StringCheck("Pankaj_Jaju") 'False
MsgBox StringCheck("Pankaj,Jaju") 'True
MsgBox StringCheck("Pankaj,Jaju 1234") 'False

You don't have to loop over every character to check whether it lies in your defined array. You just need to check whether the given character is in range of the permitted ASCII values :
ASCII value of character i >= 65 and <=90 (For upper case letters)
OR
ASCII value of character i >= 97 and <= 122 (For lower caase letters)
OR
ASCII value of character i == 44 (For comma)
OR
ASCII value of character i == 32 (For space)
You can define a check for these four conditions to avoid loop.
Public Function IsInArray(stringToBeFound As String) As Boolean
Dim i
For i = 1 to Len(stringToBeFound)
If (stringToBeFound(i) >= 65 and stringToBeFound(i) <= 90) or (stringToBeFound(i) >= 97 and stringToBeFound(i) <= 122) or
(stringToBeFound(i) = 44) or
(stringToBeFound(i) = 32) Then
IsInArray = True
Exit Function
End If
Next i
IsInArray = False
End Function

Related

insert a function to a subroutine

I need to insert a transliteration function to a subroutine that copies the contents of a document, inserts it into a temporary document and then the transliteration function should be performed. then it will be copied from the temporary document to the main one below the source text. i dont know how to insert function in a sub. which objects/methods/properties should i use?
function:
Function f(ByVal txt As String) As String
Dim RUS As String, ENG As Variant, i As Integer, b As Boolean
ENG = Array("shh", "e'", "y'", "''", "ya", "yo", "yu", "zh","ch","sh", "a", "b", "v", "g", "d", "e", "z", "i", "j", "k", "l", "m", "n", "o", "p", "r", "s", "t", "u", "f", "x", "c", "'", "Shh", "E'", "Y'", "Ya", "Yo", "Yu", "Zh", "Ch", "Sh", "A", "B", "V", "G", "D", "E", "Z", "I", "J", "K", "L", "M", "N", "O", "P", "R", "S", "T", "U", "F", "X", "C")
RUS = "щэыъяёюжчшабвгдезийклмнопрстуфхцьЩЭЫЯЁЮЖЧШАБВГДЕЗИЙКЛМНОПРСТУФХЦ"
For i = 0 To 63
If InStr(1, txt, Mid$(RUS, i + 1, 1), vbBinaryCompare) Then b = True
temp = Mid$(RUS, i + 1, 1)
txt = Replace$(txt, IIf(b, temp, ENG(i)), IIf(b, ENG(i), temp))
Next
f = txt
End Function
subroutine:
Sub test()
Dim tempDoc As Document, doc As Document
Set doc = ActiveDocument
Set tempDoc = Documents.Add
doc.Range.Copy
tempDoc.Activate
Selection.Paste
'insert function here (i guess)
tempDoc.Range.Copy
doc.Activate
With Selection
.EndKey Unit:=wdStory
.Collapse Direction:=wdCollapseEnd
End With
Selection.TypeParagraph
Selection.Paste
tempDoc.Close 0
ActiveDocument.Range.Characters.Last.Previous.Delete
End Sub
For example:
Sub test()
Dim doc As Document: Set doc = ActiveDocument
doc.Characters.Last.Text = vbcr & f(doc.Range.Text)
End Sub

Loop won't concatenate a string more than once

I'm currently doing a soundex system for homework. For the assignment, I need to replace certain letters with certain numbers. For the assignment, I'm using a do loop. The problem is that only one letter in the string is replaced with a number, while the rest of the letters besides the first one are deleted. For example, Robert is supposed to come out as "R163," but it instead comes out as "R300". I was wondering what I'm doing wrong. My code is:
Private Sub btnCompute_Click(sender As Object, e As EventArgs) Handles btnCompute.Click
Dim word As String = txtInput.Text
Dim first As String = txtInput.Text.Substring(0, 1)
Dim rest As String = txtInput.Text.Substring(1, word.Length - 1)
Dim test As String = ""
Dim combine As String = ""
Dim i As Integer = 0
Do
Select Case rest.Substring(i)
Case "a", "e", "i", "o", "u", "h", "y", "w"
test &= ""
Case "b", "f", "p", "v"
test &= "1"
Case "c", "g", "j", "k", "q", "s", "x", "z"
test &= "2"
Case "d", "t"
test &= "3"
Case "l"
test &= "4"
Case "m", "n"
test &= "5"
Case "r"
test &= "6"
End Select
i += 1
Loop Until i > rest.Length
combine = first & test
If combine.Length < 4 Then
Do While combine.Length < 4
combine &= "0"
Loop
ElseIf combine.Length > 4 Then
combine = combine.Substring(4)
End If
txtSound.Text = combine
End Sub
Trying to keep things as similar to your example... This should work.
Dim word As String = txtInput.Text
Dim test As String = String.Empty
Dim combine As String = String.Empty
For i As Integer = 1 To word.Length - 1
Select Case word.Substring(i, 1)
Case "a", "e", "i", "o", "u", "h", "y", "w"
test &= ""
Case "b", "f", "p", "v"
test &= "1"
Case "c", "g", "j", "k", "q", "s", "x", "z"
test &= "2"
Case "d", "t"
test &= "3"
Case "l"
test &= "4"
Case "m", "n"
test &= "5"
Case "r"
test &= "6"
End Select
Next
combine = (word.Substring(0, 1) & test).PadRight(4, "0")
txtSound.Text = combine

How do I check for each character to be a number or a character in PowerPoint VBA and change their fonts accordingly?

I need to look through all characters and check if they are numbers or text items. If they are of either kind, I need to change their font accordingly. I have managed to do this in excel vba using some built in functions. But seems rather impossible in powerpoint.
Its rather primitive but does work. However, oddly, some parts get done properly others don't. I am unable to figure it out.
I have used this code:
Sub FontChange()
Dim sld As Slide
Dim shp As Shape
Dim foundText As Variant
Dim findNumber As Variant
Dim findCharacter As Variant
Dim x As Long
Dim y As Long
'Dim i As Integer
'Dim j As Character
findNumber = Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9")
findCharacter = Array("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z")
For Each sld In ActivePresentation.Slides
For Each shp In sld.Shapes
If shp.HasTextFrame Then ' Not all shapes do
If shp.TextFrame.HasText Then ' the shape may contain no text
For x = LBound(findNumber) To UBound(findNumber)
Set foundText = shp.TextFrame.TextRange.Find(FindWhat:=findNumber(x))
Do While Not (foundText Is Nothing)
With foundText
.Font.Size = 18
.Font.Name = "Meta-Normal"
'.Bold = False
'.Color.RGB = RGB(255, 127, 255)
Set foundText = _
shp.TextFrame.TextRange.Find(FindWhat:="findNumber(x)", _
After:=.Start + .Length - 1)
End With
Loop
Next x
End If
End If
Next shp
Next sld
For Each sld In ActivePresentation.Slides
For Each shp In sld.Shapes
If shp.HasTextFrame Then ' Not all shapes do
If shp.TextFrame.HasText Then ' the shape may contain no text
For y = LBound(findCharacter) To UBound(findCharacter)
Set foundText = shp.TextFrame.TextRange.Find(FindWhat:=findCharacter(y))
Do While Not (foundText Is Nothing)
With foundText
.Font.Size = 18
.Font.Name = "Neo Sans Pro Light"
'.Bold = False
'.Color.RGB = RGB(255, 127, 255)
Set foundText = _
shp.TextFrame.TextRange.Find(FindWhat:="findCharacter(y)", _
After:=.Start + .Length - 1)
End With
Loop
Next y
End If
End If
Next shp
Next sld
End Sub
This might be a more elegant approach. Two private functions to individually check the text. You could combine for an OR statement, but I left as two separate items for simplicity.
Sub FontChange()
Dim sld As Slide
Dim shp As Shape
Dim x As Long
Dim y As Long
For Each sld In ActivePresentation.Slides
For Each shp In sld.Shapes
If shp.HasTextFrame Then ' Not all shapes do
If shp.TextFrame.HasText Then ' the shape may contain no text
If NumbersExist(shp.TextFrame.TextRange) Then
'if Number exists
End If
If LettersExist(shp.TextFrame.TextRange) Then
'What to do if text exists)
End If
Next shp
Next sld
End Sub
Private Function LettersExist(yourText As String) As Boolean
Dim FindCharacter As Variant, i As Integer
FindCharacter = Array("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z")
For i = 0 To 25
If InStr(1, yourText, FindCharacter(i), vbTextCompare) > 0 Then
LettersExist = True
Exit Function
End If
Next i
End Function
Private Function NumbersExist(yourText As String) As Boolean
Dim FindNumber As Variant, i As Integer
FindNumber = Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9")
For i = 0 To 9
If InStr(1, yourText, FindNumber(i), vbTextCompare) > 0 Then
NumbersExist = True
Exit Function
End If
Next i
End Function

How to validate a LEI code

I am writing a Macro to validate LEI codes.
LEI Code is:
20 char string
First 18 chars alphanumeric
Last two chars numeric
Example: F50EOCWSQFAUVO9Q8Z97
Validation
Replace all alphabetical chars in string with 2 digit number to create integer
If mod of integer divided by 97 is 1 then code valid, else invalid
I have written the below:
Sub Test()
Dim LEI_String As String
LEI_String = Range("B1")
LEI_String = Replace(LEI_String, "A", "10")
LEI_String = Replace(LEI_String, "B", "11")
LEI_String = Replace(LEI_String, "C", "12")
LEI_String = Replace(LEI_String, "D", "13")
LEI_String = Replace(LEI_String, "E", "14")
LEI_String = Replace(LEI_String, "F", "15")
LEI_String = Replace(LEI_String, "G", "16")
LEI_String = Replace(LEI_String, "H", "17")
LEI_String = Replace(LEI_String, "I", "18")
LEI_String = Replace(LEI_String, "J", "19")
LEI_String = Replace(LEI_String, "K", "20")
LEI_String = Replace(LEI_String, "L", "21")
LEI_String = Replace(LEI_String, "M", "22")
LEI_String = Replace(LEI_String, "N", "23")
LEI_String = Replace(LEI_String, "O", "24")
LEI_String = Replace(LEI_String, "P", "25")
LEI_String = Replace(LEI_String, "Q", "26")
LEI_String = Replace(LEI_String, "R", "27")
LEI_String = Replace(LEI_String, "S", "28")
LEI_String = Replace(LEI_String, "T", "29")
LEI_String = Replace(LEI_String, "U", "30")
LEI_String = Replace(LEI_String, "V", "31")
LEI_String = Replace(LEI_String, "W", "32")
LEI_String = Replace(LEI_String, "X", "33")
LEI_String = Replace(LEI_String, "Y", "34")
LEI_String = Replace(LEI_String, "Z", "35")
MsgBox Len(LEI_String)
Range("B2").Value = CCur(LEI_String) Mod 97
MsgBox CCur(LEI_String) Mod 97
End Sub
And am of course getting run-time error 6 overflow errors as the integer I am working with is 35 digits long.
Is there a way of working around this?
The LEI number is too big to fit in a Decimal type. To get the modulo, you'll have to compute the modulo on each digit once converted to base 10:
Private Sub Test()
Debug.Print IsValidLEI("F50EOCWSQFAUVO9Q8Z97") ' >> True '
Debug.Print IsValidLEI("T50EOCWSQFAUVO9Q8Z97") ' >> False '
End Sub
Public Function IsValidLEI(lei As String) As Boolean
Dim i As Long, c As Long, m As Long
For i = 1 To Len(lei) ' each character '
c = AscW(Mid(lei, i, 1)) ' get the character code (see ASCII table) '
Select Case c
Case 48 To 57 ' 0-9 -> 0-9 '
m = (m * 10 + c - 48) Mod 97 ' x10 to shift 1 digit, -48 to convert to base10 '
Case 65 To 90 ' A-Z -> 10-35 '
m = (m * 100 + c - 55) Mod 97 ' x100 to shift 2 digits, -55 to convert to base10 '
Case Else
Err.Raise 5, , "Unexpected character at " & i
End Select
Next
IsValidLEI = m = 1
End Function
Sub Test()
Dim LEI_String As String
LEI_String = Range("B1")
LEI_String = Replace(LEI_String, "A", "10")
LEI_String = Replace(LEI_String, "B", "11")
LEI_String = Replace(LEI_String, "C", "12")
LEI_String = Replace(LEI_String, "D", "13")
LEI_String = Replace(LEI_String, "E", "14")
LEI_String = Replace(LEI_String, "F", "15")
LEI_String = Replace(LEI_String, "G", "16")
LEI_String = Replace(LEI_String, "H", "17")
LEI_String = Replace(LEI_String, "I", "18")
LEI_String = Replace(LEI_String, "J", "19")
LEI_String = Replace(LEI_String, "K", "20")
LEI_String = Replace(LEI_String, "L", "21")
LEI_String = Replace(LEI_String, "M", "22")
LEI_String = Replace(LEI_String, "N", "23")
LEI_String = Replace(LEI_String, "O", "24")
LEI_String = Replace(LEI_String, "P", "25")
LEI_String = Replace(LEI_String, "Q", "26")
LEI_String = Replace(LEI_String, "R", "27")
LEI_String = Replace(LEI_String, "S", "28")
LEI_String = Replace(LEI_String, "T", "29")
LEI_String = Replace(LEI_String, "U", "30")
LEI_String = Replace(LEI_String, "V", "31")
LEI_String = Replace(LEI_String, "W", "32")
LEI_String = Replace(LEI_String, "X", "33")
LEI_String = Replace(LEI_String, "Y", "34")
LEI_String = Replace(LEI_String, "Z", "35")
MsgBox Len(LEI_String)
Range("B2").Value = Round(LEI_String / 97, 0)
MsgBox Round(LEI_String / 97, 0)
End Sub
Here is a way to validate an LEI using Regex and C#
bool IsValidLEI(string lei) {
Regex leiValidationRegex = new Regex(#"[A-Z0-9]{18}\d{2}");
return leiValidationRegex.IsMatch(lei);
}

Format phone numbers leaving only alphanumeric characters and then follow a format

It's my first time posting here. I am currently exploring VBA and I wanted to make a macro that formats phone numbers and translates it into a standard format. All special characters other that numbers and letters should be removed. I'm so sorry for my english is not that good. Here is an example.
The scenario must look like this, I select a range,
8009228080
(900) (CAT) BABA
(+1) (900) (289) (9000)
900.900.9000
then I click the button where the macro is assigned then it goes like this
800-922-8080
900-228-2222
900-289-9000
900-900-9000
The output must be only ###-###-#### (3 numbers ' - ' 3 numbers ' - ' 4 numbers)
Letter must be translated into following
ABC = 2, DEF = 3, GHI = 4, JKL = 5, MNO = 6, PQRS = 7, TUV = 8, WXYZ = 9
I tried looking it up and here is my try:
Sub PhoneFormat()
Dim StSel As Range
Dim EndSel As Range
On Error Resume Next
xTitleId = "Format Phone Numbers"
Set EndSel = Application.Selection
Set EndSel = Application.InputBox("Range", xTitleId, EndSel.Address, Type:=8)
I want to change this part as I want to select the range first, then click the button then the macro is applied
For Each StSel In EndSel
StSel.Value = Application.WorksheetFunction.Substitute(StSel.Value, "+", "")
StSel.Value = Application.WorksheetFunction.Substitute(StSel.Value, "+1", "")
StSel.Value = Application.WorksheetFunction.Substitute(StSel.Value, "-", "")
StSel.Value = Application.WorksheetFunction.Substitute(StSel.Value, ".", "")
StSel.Value = Application.WorksheetFunction.Substitute(StSel.Value, "(", "")
StSel.Value = Application.WorksheetFunction.Substitute(StSel.Value, ")", "")
StSel.Value = Application.WorksheetFunction.Substitute(StSel.Value, " ", "")
If (Len(StSel) > 10) Then
StSel = Right(StSel, 10)
End If
StSel = Left(StSel, 3) & "-" & Mid(StSel, 4, 3) & "-" & Right(StSel, 4)
Next
End Sub
I think this could be optimized into much simplier code but I can't do it. This code also can't replace letters to numbers. Thanks in advance an I hope anyone would answer this.
Here is an example how you could do it with Regular Expressions:
Option Explicit
Public Sub test()
Debug.Print FormatWithRegEx("(900) (CAT) BABA")
Debug.Print FormatWithRegEx("(+1) (900) (289) (9000)")
Debug.Print FormatWithRegEx("900.900.9000")
Debug.Print ReplaceCharactersWithRegEx(FormatWithRegEx("(900) (CAT) BABA"))
'or dircetly implement ReplaceCharactersWithRegEx in FormatWithRegEx
End Sub
Public Function FormatWithRegEx(InputString As String) As String
Dim objRegEx As Object
Set objRegEx = CreateObject("vbscript.regexp")
Dim arrPatterns() As Variant
arrPatterns = Array( _
"([A-Z0-9]{10})", _
"\(?([A-Z0-9]{3})\)? \(?([A-Z0-9]{3})\)? \(?([A-Z0-9]{4})\)?", _
"([A-Z0-9]{3})\.([A-Z0-9]{3})\.([A-Z0-9]{4})" _
)
Dim Pattern As Variant
For Each Pattern In arrPatterns
With objRegEx
.Global = True
.IgnoreCase = True
.MultiLine = False
.Pattern = Pattern
Dim objMatches As Object
Set objMatches = .Execute(InputString)
End With
If objMatches.Count = 1 Then
With objMatches(0)
If .SubMatches.Count = 3 Then
FormatWithRegEx= .SubMatches(0) & "-" & .SubMatches(1) & "-" & .SubMatches(2)
End If
End With
End If
If FormatWithRegEx <> vbNullString Then Exit For
Next Pattern
'to implement ReplaceCharactersWithRegEx uncomment …
'FormatWithRegEx = ReplaceCharactersWithRegEx(FormatWithRegEx)
End Function
It recognizes the 3 given patterns in the test. Translation from characters into numbers still has to be done.
Here is a pure RegEx Replace example
Public Function ReplaceCharactersWithRegEx(InputString As String) As String
InputString = RegExReplace(InputString, "[ABC]{1}", "2")
InputString = RegExReplace(InputString, "[DEF]{1}", "3")
InputString = RegExReplace(InputString, "[GHI]{1}", "4")
InputString = RegExReplace(InputString, "[JKL]{1}", "5")
InputString = RegExReplace(InputString, "[MNO]{1}", "6")
InputString = RegExReplace(InputString, "[PQRS]{1}", "7")
InputString = RegExReplace(InputString, "[TUV]{1}", "8")
InputString = RegExReplace(InputString, "[WXYZ]{1}", "9")
ReplaceCharactersWithRegEx = InputString
End Function
Private Function RegExReplace(InputString, Pattern, Replace) As String
Dim objRegEx As Object
Set objRegEx = CreateObject("vbscript.regexp")
With objRegEx
.Global = True
.IgnoreCase = True
.MultiLine = False
.Pattern = Pattern
Dim objMatches As Object
Set objMatches = .Execute(InputString)
End With
RegExReplace = objRegEx.Replace(InputString, Replace)
End Function
//Edit
made it case insensitive with .IgnoreCase = True
//Edit2
A Selection Loop Example
Dim cl As Range
For Each cl In Selection 'instead of Selection you can also use a defined Range("A1:A50")
Dim FormattedValue As String
FormattedValue = FormatWithRegEx(cl.value)
If FormattedValue <> vbNullString Then 'don't delete if formatting wasn't successful
cl.value = FormatWithRegEx(cl.value)
End If
Next cl
Taking PEH's answer and adding the Conversion of Letters to Numbers:
Option Explicit
Public Sub test()
Dim ws As Worksheet: Set ws = Sheets("Sheet1")
Dim rng As Range
Dim cell As Range
Set rng = Selection
For Each cell In rng
cell.Value = ConvertLetters(FormatWithRegEx(cell.Value))
Next
End Sub
Public Function ConvertLetters(FormattedString As String) As String
Dim J As Long, Digit As Variant
For J = 1 To Len(FormattedString)
Digit = UCase(Mid(FormattedString, J, 1))
Select Case Digit
Case "A" To "P"
Digit = Chr((Asc(Digit) + 1) \ 3 + 28)
Case "Q"
Digit = "7"
Case "R" To "Y"
Digit = Chr(Asc(Digit) \ 3 + 28)
Case "Z"
Digit = "9"
End Select
Mid(FormattedString, J, 1) = Digit
Next J
ConvertLetters = FormattedString
End Function
Public Function FormatWithRegEx(InputString As String) As String
Dim objRegEx As Object
Set objRegEx = CreateObject("vbscript.regexp")
Dim arrPatterns() As Variant
arrPatterns = Array( _
"\(([a-zA-Z0-9]{3})\) \(([a-zA-Z0-9]{3})\) ([a-zA-Z0-9]{4})", _
"\(([a-zA-Z0-9]{3})\) \(([a-zA-Z0-9]{3})\) \(([a-zA-Z0-9]{4})\)", _
"([a-zA-Z0-9]{3})\.([a-zA-Z0-9]{3})\.([a-zA-Z0-9]{4})" _
)
Dim Pattern As Variant
For Each Pattern In arrPatterns
With objRegEx
.Global = True
.IgnoreCase = True
.MultiLine = False
.Pattern = Pattern
Dim objMatches As Object
Set objMatches = .Execute(InputString)
End With
If objMatches.Count = 1 Then
With objMatches(0)
If .SubMatches.Count = 3 Then
FormatWithRegEx = .SubMatches(0) & "-" & .SubMatches(1) & "-" & .SubMatches(2)
End If
End With
End If
If FormatWithRegEx <> vbNullString Then Exit For
Next Pattern
End Function
UPDATE:
The following will format your phone numbers as expressed in your comments (taking Thom's answer and adding the Selection):
Sub PhoneFormat()
Dim myLen As Long
Dim i As Long
Dim myNum As String
Dim newNum
Dim ws As Worksheet: Set ws = Sheets("Sheet1")
Dim rng As Range
Dim cell As Range
Set rng = Selection
For Each cell In rng
' Loop through characters, converting values
If Len(cell.Value) > 0 Then
For i = 1 To Len(cell.Value)
Select Case Mid(cell.Value, i, 1)
Case "0"
myNum = "0"
Case "1"
myNum = "1"
Case "2"
myNum = "2"
Case "3"
myNum = "3"
Case "4"
myNum = "4"
Case "5"
myNum = "5"
Case "6"
myNum = "6"
Case "7"
myNum = "7"
Case "8"
myNum = "8"
Case "9"
myNum = "9"
Case "A", "B", "C", "a", "b", "c"
myNum = "2"
Case "D", "E", "F", "d", "e", "f"
myNum = "3"
Case "G", "H", "I", "g", "h", "i"
myNum = "4"
Case "J", "K", "L", "j", "k", "l"
myNum = "5"
Case "M", "N", "O", "m", "n", "o"
myNum = "6"
Case "P", "Q", "R", "S", "p", "q", "r", "s"
myNum = "7"
Case "T", "U", "V", "t", "u", "v"
myNum = "8"
Case "W", "X", "Y", "Z", "w", "x", "y", "z"
myNum = "9"
Case " ", "-", "."
myNum = "-"
Case Else
myNum = ""
End Select
newNum = newNum & myNum
Next i
End If
cell.Value = Right(newNum, 12)
Next
End Sub
I have now amended the script to work with a selected range and it will also convert all given examples.
It is simple to read and amend for other purposes which maybe useful to somebody, that is why I am posting it.
The script uses Case Else to remove characters that are not defined, converting the ones that are required.
Sub PhoneFormatRange()
Dim myLen As Long
Dim i As Long
Dim myNum As String
Dim newNum As String
Dim selectedRng As Range
Dim celRng As Range
Dim strLeft As String
Dim strMid As String
Dim strRight As String
' Find the Selected Range and for each cell in the selected range run the cade and repeat.
Set selectedRng = Application.Selection
For Each celRng In selectedRng.Cells
' Convert Cell value to an array
myLen = Len(celRng.Value)
ReDim Carray(Len(celRng.Value))
For i = 0 To myLen
Carray(i) = Mid(celRng.Value, i + 1, 1)
Next
' Loop through array, converting values
If myLen > 0 Then
For i = 0 To myLen
Select Case Carray(i)
Case "0"
myNum = "0"
Case "1"
myNum = "1"
Case "2"
myNum = "2"
Case "3"
myNum = "3"
Case "4"
myNum = "4"
Case "5"
myNum = "5"
Case "6"
myNum = "6"
Case "7"
myNum = "7"
Case "8"
myNum = "8"
Case "9"
myNum = "9"
Case "A", "B", "C", "a", "b", "c"
myNum = "2"
Case "D", "E", "F", "d", "e", "f"
myNum = "3"
Case "G", "H", "I", "g", "h", "i"
myNum = "4"
Case "J", "K", "L", "j", "k", "l"
myNum = "5"
Case "M", "N", "O", "m", "n", "o"
myNum = "6"
Case "P", "Q", "R", "S", "p", "q", "r", "s"
myNum = "7"
Case "T", "U", "V", "t", "u", "v"
myNum = "8"
Case "W", "X", "Y", "Z", "w", "x", "y", "z"
myNum = "9"
Case " ", "-", "."
myNum = "-"
Case Else
myNum = ""
End Select
newNum = newNum & myNum
Next i
End If
' Check the length of the string and if it requals 10 then add the hypens
If Len(newNum) = 10 Then
strLeft = Left(newNum, 3)
strMid = Mid(newNum, 4, 3)
strRight = Right(newNum, 4)
newNum = strLeft & "-" & strMid & "-" & strRight
End If
' Set the cell value within the range to 12 right most characters of the string
celRng.Value = Right(newNum, 12)
' Clear newNum before repeating
newNum = ""
' Go back to celRng and repeat until all the cells within the selection is complete
Next celRng
End Sub
I was also writing a regular expression as PEH did. But my approach was a bit different. Only posting it because it was fun to code this piece and it maybe helps.
I also used Xabiers ConvertLetters function because it does a good job and the code is a really good approach.
My approach to the regular expression was to match ALL criterias in one expression. So the pattern I defined finds all your defined possibilities. This forced me to make some extra replacements though so I extended Xabiers code a bit.
Sub correctNumbers()
Dim i As Long, J As Long
Dim sEXP As String
Dim rng As Range
Dim oRegEx As Object, oMatch As Object
' create object for regular expressions
Set oRegEx = CreateObject("vbscript.regexp")
' supposed you have a sheet called "Sheet1" - change sheetname and range according to your needs
Set rng = ThisWorkbook.Sheets("Sheet1").Range("A2:A4")
' run through every entry in range
For i = 1 To rng.Rows.Count
With oRegEx
.Global = True
.IgnoreCase = False
' define pattern as desribed by you needs
.Pattern = "([\(]?[0-9]{3}[\)]?[\s\.]?[\(]?[A-Z0-9]{3}[\)]?[\s\.]?[\(]?[A-Z0-9]{4}[\)]?)"
Set oMatch = .Execute(rng(i, 1).Value)
If oMatch.Count <> 0 Then
sEXP = oMatch(0)
If Len(sEXP) = 10 Then
sEXP = Left(sEXP, 3) & "-" & Right(Left(sEXP, 6), 3) & "-" & Right(sEXP, 4)
Else
sEXP = ConvertLetters(oMatch(0))
End If
Else
sEXP = ""
End If
End With
' write result in column B
ThisWorkbook.Sheets("Sheet1").Range("B" & i + 1).Value = sEXP
Next i
End Sub
Public Function ConvertLetters(FormattedString As String) As String
Dim J As Long, Digit As Variant
For J = 1 To Len(FormattedString)
Digit = UCase(Mid(FormattedString, J, 1))
Select Case Digit
Case "A" To "P"
Digit = Chr((Asc(Digit) + 1) \ 3 + 28)
Case "Q"
Digit = "7" 'May want to change
Case "R" To "Y"
Digit = Chr(Asc(Digit) \ 3 + 28)
Case "Z"
Digit = "9" 'May want to change
' added as my regular expression finds complete number including dots, spaces and braces
Case ".", " "
Digit = "-"
End Select
Mid(FormattedString, J, 1) = Digit
Next J
' added repalce as my regular expression finds complete number including dots, spaces and braces
ConvertLetters = Replace(Replace(FormattedString, "(", ""), ")", "")
End Function