Loop won't concatenate a string more than once - vb.net

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

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

A string contains certain characters only

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

VBA implementing a better script with minimal editing

This script is used on a laser machine to put date on product and letter associated with month/year. There Is a cycle in the code that needs to be followed. I have tried doing this code on an online VB compiler and get nothing but errors. I do want to note this code does work in the software used to put the Key code on the product. Q and I needed to be omitted from the code and yes I do know there is an I in the code for 2001 it is wrong. There is 2 cycle for the months Current Cycle is 2 and on Jan 2020 it will be cycle 1 again which means Jan-Dec 2020 will now be letter N-Z omitting I and Q. (CORRECTION Nov 17 2019) Jan 2020 will start with A-M not N-Z omitting I.
Project.ProcessActiveItem
Document.Show
Project.UpdateViews
End Sub
strWeekday = "%d"
strMOnth = Month(Now)
strYear = Year(Now)
If strMOnth = "1" Then strMOnthLetter = "N" End If
If strMOnth = "2" Then strMOnthLetter = "O" End If
If strMOnth = "3" Then strMOnthLetter = "P" End If
If strMOnth = "4" Then strMOnthLetter = "R" End If
If strMOnth = "5" Then strMOnthLetter = "S" End If
If strMOnth = "6" Then strMOnthLetter = "T" End If
If strMOnth = "7" Then strMOnthLetter = "U" End If
If strMOnth = "8" Then strMOnthLetter = "V" End If
If strMOnth = "9" Then strMOnthLetter = "W" End If
If strMOnth = "10" Then strMOnthLetter = "X" End If
If strMOnth = "11" Then strMOnthLetter = "Y" End If
If strMOnth = "12" Then strMOnthLetter = "Z" End If
If strYear = "1996" Then strYearLetter = "D" End If
If strYear = "1997" Then strYearLetter = "E" End If
If strYear = "1998" Then strYearLetter = "F" End If
If strYear = "1999" Then strYearLetter = "G" End If
If strYear = "2000" Then strYearLetter = "H" End If
If strYear = "2001" Then strYearLetter = "I" End If
If strYear = "2002" Then strYearLetter = "J" End If
If strYear = "2003" Then strYearLetter = "K" End If
If strYear = "2004" Then strYearLetter = "M" End If
If strYear = "2005" Then strYearLetter = "N" End If
If strYear = "2006" Then strYearLetter = "O" End If
If strYear = "2007" Then strYearLetter = "P" End If
If strYear = "2008" Then strYearLetter = "R" End If
If strYear = "2009" Then strYearLetter = "S" End If
If strYear = "2010" Then strYearLetter = "T" End If
If strYear = "2011" Then strYearLetter = "U" End If
If strYear = "2012" Then strYearLetter = "V" End If
If strYear = "2013" Then strYearLetter = "W" End If
If strYear = "2014" Then strYearLetter = "X" End If
If strYear = "2015" Then strYearLetter = "Y" End If
If strYear = "2016" Then strYearLetter = "Z" End If
If strYear = "2017" Then strYearLetter = "A" End If
If strYear = "2018" Then strYearLetter = "B" End If
If strYear = "2019" Then strYearLetter = "C" End If
Set YWWS1 = Document.CreateString(5)
YWWS1.Text = strWeekday & strMOnthLetter & strYearLetter
YWWS1.Update
Set YWWS2 = Document.CreateString(6)
YWWS2.Text = strWeekday & strMOnthLetter & strYearLetter
YWWS2.Update
Document.Show
Project.UpdateViews
Assuming that 2017 is our origin point and the general formula for assigning letters and numbers remain constant: ie: 2020 should be D
We can convert the difference and remainder in years by 26 to identify at what point of the iteration we're in.
For example 2020 is 3 years after 2017 (well adjust this value by 1 because 2020-2017 is zero base where A-Z starts with 1).
3+1=4 means we should provide D.
By using ASCII/CHR conversions we can simply add 64 to our remainder value + 1 to get the letter for that year iteration.
Similar logic is utilized for months, but assuming the codes are constant(with the offset beginning at N accounted for by adding 14 to the ASCII value before conversion). If these iterate let me know and we can adjust based on the iteration pattern.
I would update your code to the following:
Project.ProcessActiveItem
Document.Show
Project.UpdateViews
End Sub
strWeekday = "%d"
'strYear = year(Now)
'strMonth = Month(Now)
Dim intYear As Integer: intYear = year(Now)
Dim intMonth As Integer: intMonth = Month(Now)
Dim intYearIter As Integer
Dim intMonthIter As Integer
'Get current month and add 14 to align with sequence
intMonthIter = Month(Now) + 14
'If current month iteration is 17 (Q) skip to next
If intMonthIter = 17 Then
intMonthIter = intMonthIter + 1
End If
strMonthLetter = Chr(intMonthIter + 64)
'Get iteration of supplied year
If intYear >= 2017 Then
intYearIter = (intYear - 2017 + 1) Mod 26
Else
intYearIter = 26 - ((2017 - intYear + 1) Mod 26)
End If
'If iteration is 17(Q) or 9(I) skip to next
If intYearIter = 17 Or intYearIter = 9 Then
intYearIter = intYearIter + 1
End If
strYearLetter = Chr(intYearIter + 64)
Set YWWS1 = Document.CreateString(5)
YWWS1.Text = strWeekday & strMOnthLetter & strYearLetter
YWWS1.Update
Set YWWS2 = Document.CreateString(6)
YWWS2.Text = strWeekday & strMOnthLetter & strYearLetter
YWWS2.Update
Document.Show
Project.UpdateViews
Replace most of this code with a function that stores the codes in arrays and indexes the arrays based on the current month and year. This way the codes are flexible, as they don't have to be sequential and more codes can be added later.
Public Function GetDateCode() As String
Dim strMoLetter() As Variant, strYrLetter() As Variant
strMoLetter = Array("N", "O", "P", "R", "S", "T", "U", "V", "W", "X", "Y", "Z")
strYrLetter = Array("D", "E", "F", "G", "H", "I", "J", "K", "M", "N", "O", "P", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A", "B", "C")
Dim intMo As Long, intYr As Long
intMo = Month(Now): intYr = Year(Now)
GetDateCode = "%d" & strMoLetter(intMo - 1) & strYrLetter(intYr - 1996)
End Function
Note that in this case letters "L" and "Q" are missing.
Now call this function as follows
Dim code As String
code = GetDateCode()
Set YWWS1 = Document.CreateString(5)
YWWS1.Text = code
YWWS1.Update
Set YWWS2 = Document.CreateString(6)
YWWS2.Text = code
YWWS2.Update
Document.Show
Project.UpdateViews

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

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