I have an excel file with cells containing some comments like:
txxxxx:10/15/2019 11:38:48 AM - Customer ID: xxxxx
) 1st contact - Text only sent to Mob TN xxxxxxw/Ref &TN
Txxxxxx:10/18/2019 1:34:12 PM -
Called BEST CBR xxxxxx, Spoke to Mr, he said they have been busy & unable to review/discuss yet. Offered to text him our direct info, they will check online &/or call us soon.
An SMS message has been successfully sent to Gull Family at xxxxxx
OK WITH FINAL CB next week.
The text could be anything potentially containing multiple date time fields.
I am trying to extract all such date occurrences from each cell and put them in different columns
I tried using =regExFind and =regExExtract. For instance:
=RegExFind($Cell,"\d{2}/\d{2}/\d{4}")
I also tried =Text($cell, dd/mm/yyyy)
However, neither approach is working.
Is there a way in excel to do a RegEx Extract and if so how to achieve that?
If not, what is the best way to extract all datetime fields?
UPDATE:
This is the code I have used:
Function RegexExtract(ByVal text As String, _
ByVal extract_what As String, _
Optional separator As String = ", ") As String
Dim allMatches As Object
Dim RE As Object
Set RE = CreateObject("vbscript.regexp")
Dim i As Long, j As Long
Dim result As String
RE.pattern = extract_what
RE.Global = True
Set allMatches = RE.Execute(text)
For i = 0 To allMatches.count - 1
For j = 0 To allMatches.Item(i).submatches.count - 1
result = result & (separator & allMatches.Item(i).submatches.Item(j))
Next
Next
If Len(result) <> 0 Then
result = Right$(result, Len(result) - Len(separator))
End If
RegexExtract = result
End Function
But no Output.
As your post is not very explicit, my answer can not be more too.
Try this one:
Dim regex As Object, str As String
Set regex = CreateObject("VBScript.RegExp")
With regex
.Pattern = "([0-9]+)/([0-9]+)/([0-9]+)"
.Global = True
End With
str = "Whatever string you have"
Set matches = regex.Execute(str)
For Each match In matches
Debug.Print match.Value
Next match
So you will need to loop it in your range. str should be your cell on the loop and instead of Debug.Print you should bring this value to whatever cell like Worksheet("?").Cells(i,j).Value = match.Value.
Hope it helps
A bit of a workaround...instead of using RegEx the idea is to find the "AM"s and "PM"s in the cell and copy paste the string of 19/20 characters before them in the column "Date Extraction". One of the limitations of this method is clearly that could work only if AM and PM are always present in the date format of your messages.
Sub ExtractDates()
Dim myRange, cell As Range
Dim StringInCell, MyDate As String
Dim DateExtrColNum, i, j As Integer
Set myRange = Worksheets("YourSheetName").UsedRange
DateExtrColNum = myRange.Columns(myRange.Columns.Count).Column
Cells(1, DateExtrColNum + 1).Value = "Date Extraction"
j = 2
For Each cell In myRange
If Not cell.Find("AM") Is Nothing Or Not cell.Find("PM") Is Nothing Then
StringInCell = cell.Value
i = 1
Do While InStr(i, StringInCell, "AM") <> 0 Or InStr(i, StringInCell, "PM") <> 0
If InStr(i, StringInCell, "AM") <> 0 Then
MyDate = Mid(StringInCell, InStr(i, StringInCell, "AM") - 20, 20)
If InStr(1, MyDate, ":") = 1 Then
MyDate = Right(MyDate, 19)
End If
i = InStr(i, StringInCell, "AM") + 1
Else: MyDate = Mid(StringInCell, InStr(i, StringInCell, "PM") - 20, 20)
If InStr(1, MyDate, ":") = 1 Then
MyDate = Right(MyDate, 19)
End If
i = InStr(i, StringInCell, "PM") + 1
End If
Cells(j, DateExtrColNum + 1).Value = MyDate
j = j + 1
Loop
End If
Next
End Sub
Related
I´m trying to find a way to use Instr to work only with words that have a specific font.
I´m currently using a code that allows me to find differences between two paragraphs and show the changes on another column by chainging the words that are the same to the color green.
The problem is that when using Instr it only finds the first occurence of a word. But with the paragraphs I´m using, the words appear multiple times:
myLastRow = Cells(Rows.Count, "G").End(xlUp).Row
For I = 3 To myLastRow
strTemp = " "
WordsA = Split(Range("F" & I).Text, " ")
Debug.Print WordsA
WordsB = Split(Range("H" & I).Text, " ")
Debug.Print WordsB
For ndxB = LBound(WordsB) To UBound(WordsB)
For ndxA = LBound(WordsA) To UBound(WordsA)
If StrComp(WordsA(ndxA), WordsB(ndxB), vbTextCompare) = 0 Then
FindText = WordsA(ndxA)
Debug.Print FindText
Set TextRange = Range("H" & I)
fontColor = 4
'FindText.Font.ColorIndex = fontColor
For Each part In TextRange
lenOfpart22 = InStr(1, TextRange, FindText, 1)
lenPart = Len(FindText)
part.Characters(Start:=lenOfpart22, Length:=lenPart).Font.ColorIndex = fontColor
Next part
Exit For
End If
Next ndxA
Next ndxB
Next I
What I need is for the Instr to only search the word if its fond is 0 (black).
TextRange is the paragraph. Usually more than 500 caracters long
FindText is the word that I´m searching
This is an example of the problem I´m having:
In this paragraph you can see how some words appear in green. These are the words that are the same on the two paragraphs that I´m comparing (columns F and G). There are some words such as: aeqqw, SAWR, SIGMEL... that are different. The problem is that Instr only finds the first occurrence of a word. That´s why I want a condition were if the word is green, it won´t be considered in the instr and will move on to find the next word.
In the picture you can see that the first "El" is in green, but the rest aren´t. This is because when it searches for the second, thrid, fourth... "el" it comes back to the first "el".
Please, use the next function to do what (I understood) you need (playing with arrays...):
Sub WordsComp(cell1 As Range, cell2 As Range) 'punctuation characters eliminated
Dim arr1() As String, arr2() As String, arrMtch() As String, mtch, El
Dim strArr As String, i As Long, cleanWord As String, endPlus As Long
arr1 = Split(cell1.value): arr2 = Split(cell2.value) 'split the two cells content by words
For Each El In arr1 'iterate between the first cell words
For i = 0 To UBound(arr2)
cleanWord = EndingCharsOut(CStr(El))
endPlus = Len(cleanWord) - Len(El)
If EndingCharsOut(CStr(arr2(i))) = cleanWord Then 'when a match has been found:
arrMtch = Split(cell2, , i + 1, vbTextCompare) 'split the range only up to the searched word (plus the rest of the string)
'eliminate the last element of the array:
arrMtch(UBound(arrMtch)) = "##$%": arrMtch = filter(arrMtch, "##$%", False)
strArr = Join(arrMtch, "|") 'join the array elements to obtain the necessary start, before the word to be colored
cell2.Characters(start:=Len(strArr) + 2, length:=Len(El) + endPlus).Font.Color = vbGreen '+ 2 because of the 1D zero based array and a space
End If
Next i
Next
End Sub
Private Function EndingCharsOut(strMatch As String) As String 'eliminates ending punctuation characters (,.?:;)
With CreateObject("Vbscript.RegExp")
.Pattern = "[.,/?:;]$"
If .test(strMatch) Then
EndingCharsOut = (.Replace(strMatch, ""))
Else
EndingCharsOut = strMatch
End If
End With
End Function
The above Sub should be called by the next one:
Sub testWordsCompare()
Dim ws As Worksheet, rng As Range, lastR As Long, i As Long
Set ws = ActiveSheet
lastR = ws.Range("F" & ws.rows.count).End(xlUp).row
Set rng = ws.Range("F2:G" & lastR)
rng.Columns(2).Font.Color = 0 'make the font color black (default)
Application.EnableEvents = False: Application.ScreenUpdating = False
For i = 1 To rng.rows.count
WordsComp rng.rows(i).cells(1, 1), rng.rows(i).cells(1, 2)
Next i
Application.EnableEvents = True: Application.ScreenUpdating = True
MsgBox "Ready..."
End Sub
The function compares words even containing punctuation (comma, dot, question mark, ":", ";") at the end...
A faster solution but not so compact and easy to be understood, would be the next classic one:
Sub compWdClassic(cell1 As Range, cell2 As Range)
Dim iStart1 As Long, iEnd1 As Long, iStart2 As Long, oldStart As Long, strWd As String
Dim boolEnd As Boolean, boolOut As Boolean, i As Long, frstW As Boolean, midleW As Boolean
iStart1 = 1 'initialize starting position for Cell1 string
Do While Not boolEnd
iEnd1 = InStr(iStart1, cell1, " ", vbBinaryCompare) 'determine the ending of the word to be returned
strWd = Mid(cell1, iStart1, IIf(iEnd1 > 0, iEnd1 - iStart1, Len(cell1) - iStart1 + 1)) ' extraxting the word to be checked
If iEnd1 > 0 Then iStart1 = iEnd1 + 1 Else: boolEnd = True 'determine if is it about the last word (or not)...
strWd = EndingCharsOut(strWd) 'clean the word ending
midleW = False: boolOut = False: iStart2 = 1 'initialize the necessary variables
Do While Not boolOut 'loop in cell2 value string
If Not frstW And iStart2 = 1 Then 'if not a first word has been found:
iStart2 = InStr(IIf(iStart2 = 0, 1, iStart2), cell2, strWd & " ", vbBinaryCompare) 'check against a word without a space in front
If iStart2 > 0 Then frstW = True 'first word in the sentence. If such a word found, make the boolean variable True
Else
oldStart = iStart2 'memorize the previous value of iStart2
iStart2 = InStr(iStart2 + 1, cell2, " " & strWd & " ", vbBinaryCompare) 'search if a word with spaces at both sides
If iStart2 > 0 Then midleW = True 'if founded, make the boolean variable True
If oldStart > 0 And midleW Then 'if nothing found before, but a pevious word with spaces of both sides has been found:
If iStart2 = 0 Then iStart2 = InStr(oldStart, cell2, " " & strWd, vbBinaryCompare): _
If iStart2 > 0 And iStart2 + Len(strWd) = Len(cell2) Then boolOut = True Else: iStart2 = 0: boolOut = True: 'if the last word or only part of a word
ElseIf oldStart = 0 And Not midleW Then
If iStart2 = 0 Then iStart2 = InStr(oldStart + 1, cell2, " " & strWd, vbBinaryCompare):
If iStart2 > 0 Then boolOut = True: ' last word and loop must be exited
End If
End If
If iStart2 > 0 Then
cell2.Characters(iStart2 + IIf(boolOut, 1, IIf(frstW And Not midleW, 0, 1)), Len(strWd)).Font.Color = vbRed 'do the job
iStart2 = iStart2 + Len(strWd) + 1 'increment the variable for the next search
Else
If (frstW And Not boolOut) Or (Not frstW And Not midleW And Not boolOut) Then Exit Do 'exiting loop if conditions are met
End If
Loop
Loop
End Sub
It uses the same EndingCharsOut function to clear punctuation characters. You only must call this Sub instead of previous. I mean, replace:
WordsComp rng.rows(i).cells(1, 1), rng.rows(i).cells(1, 2)
in testWordsCompare sub with:
compWdClassic rng.rows(i).cells(1, 1), rng.rows(i).cells(1, 2)
Please, send some feedback after testing them...
If I have the below info all contained in a single cell and I want to split it into separate cells. I understand how to use the space as a delimiter but in this case, the name also has spaces and I want the name to stay together in a single cell. To further complicate the matter, the name is not always just first and last, it can also include middle so is not always a standard two names.
2172571122 Jane Doe 3143332222 John Doe
2172242237 Mary Mixer 2223334444 Mike M Martin
Want it to end up looking like this:
Cell 1 = 2172242237
Cell 2 = Mary Mixer
Cell 3 = 2223334444
Cell 4 = Mike M Martin
Any suggestions?
This regex based function alternates each split between numbers and text (words).
Option Explicit
Function customSplit(str As String, _
Optional ndx As Integer = 1) As Variant
Static rgx As Object, cmat As Object
Set rgx = CreateObject("VBScript.RegExp")
With rgx
.Global = True
.MultiLine = True
.IgnoreCase = True
If CBool(ndx Mod 2) Then
.Pattern = "[0-9]{10}"
ndx = (ndx + 1) \ 2
Else
.Pattern = "[A-Z]{1,9}\s[A-Z]{1,9}[\s[A-Z]{1,9}]?"
ndx = ndx \ 2
End If
If .test(str) Then
Set cmat = .Execute(str)
If ndx <= cmat.Count Then
customSplit = cmat.Item(ndx - 1)
End If
End If
End With
End Function
You could try:
Option Explicit
Sub test()
Dim strToSplit As String, strImport As String
Dim arrwords As Variant
Dim i As Long, counter As Long
With ThisWorkbook.Worksheets("Sheet1")
strToSplit = .Range("A1").Value
arrwords = Split(strToSplit, " ")
counter = 1
For i = LBound(arrwords) To UBound(arrwords)
If IsNumeric(arrwords(i)) = True Then
strImport = arrwords(i)
.Cells(3, counter).Value = strImport
counter = counter + 1
ElseIf Not IsNumeric(arrwords(i)) = True Then
If Not IsNumeric(.Cells(3, counter - 1).Value) Then
strImport = .Cells(3, counter - 1) & " " & arrwords(i)
.Cells(3, counter - 1).Value = strImport
counter = counter
Else
strImport = arrwords(i)
.Cells(3, counter).Value = strImport
counter = counter + 1
End If
End If
Next
End With
End Sub
Results look like this:
I have a few ideas on what you could do.
1) Read a Line
Do a split(line, " ") and loop through the indecies while performing a isNumeric() on each split value. If not, then add to a string Array() and set a flag to true.
Then, if isnumeric then, expect another name and set flag to true.
2) Read a line.
Then, loop through each character performing an isnumeric and if not then add that character to a string Array() and set flag until isnumeric again, etc....
I hope that helps or at least gets you in the right direction.
Additional variant to posted already:
Sub ZZZ()
Dim dic As Object: Set dic = CreateObject("Scripting.Dictionary")
Dim num$, cl As Range, data As Range, key, x
Dim Result As Worksheet
Set data = Range([A1], Cells(Rows.Count, "A").End(xlUp))
For Each cl In data
x = "": num = "":
For Each x In Split(cl, " ")
If IsNumeric(x) Then
num = x
dic.Add x, ""
ElseIf x <> "" And num <> "" Then
dic(num) = Trim(dic(num) & " " & x)
End If
Next x
Next cl
Set Result = Worksheets.Add
With Result
.Name = "Result " & Replace(Now, ":", "-")
x = 1
For Each key In dic
.Cells(x, "A").Value2 = key
.Cells(x, "B").Value2 = dic(key)
x = x + 1
Next key
.Columns("A:B").AutoFit
End With
End Sub
test:
I have this dates from DB and I want to fix the date in VBA excel because excel switch the date with month when filter the column
27/08/2018
31/08/2018
12/9/2018
2/8/2018 wrong date reported at filter in excel need 02/08/2018
6/8/2018 wrong date reported at filter in excel need 06/08/2018
13/08/2018
17/08/2018
20/08/2018
20/08/2018
I have tried this
For i = 2 To lastRow
Dim fDate As Date
Dim dayF As String
Dim monthF As String
Dim yearF As String
Set r = Cells(i, Column_DateStamp)
strDate = Split(r.Text, "/")
dayF = CStr(Format(strDate(0), "00"))
monthF = CStr(Format(strDate(1), "00"))
yearF = CStr(Format(strDate(2), "0000"))
fDate = Format(DateSerial(strDate(2), CStr(Format(strDate(1), "00")), CStr(Format(strDate(0), "00"))), "dd/mm/yyyy")
r.Clear
r.Value = fDate
Next i
The date formats do not match your local date format and as such Excel is trying to convert.
You need to either put the date in and format it appropriately or make the cell text so excel does not try to convert.
Dim i As Long
For i = 2 To lastRow
Dim fDate As Date
Dim r As Range
Set r = Cells(i, Column_DateStamp)
strDate = Split(r.Text, "/")
fDate = DateSerial(strDate(2), strDate(1), strDate(0))
r.Clear
'True date - comment out if you want string
r.NumberFormat = "dd/mm/yyyy"
r.Value2 = fDate
'String - Uncomment if you want string
' r.NumberFormat = "#"
' r.Value2 = Format(fDate, "dd/mm/yyyy")
Next i
Examining your screenshot, the problem is consistent with your Windows Regional Settings being MDY and the Database settings being DMY. This will always result in incorrect action by Excel.
Whoever wrote the ERP application should be able to make the change to input, to Excel, an unambiguous date format; or trigger the excel text import wizard at the time of import.
You can try this macro in the meantime. It should work, but read the notes carefully for possible pitfalls:
Option Explicit
Sub ConvertDates()
'converts dates that have been mismatched MDY / DMY
'Assumes dates are all in selected column
' Only need to select a single cell in the column
' will place results in a column next to original data
' If adjacent column is not blank, a column will be inserted
'Figures out the original format by analyzing a "text" date
'Time components are converted directly. This might be OK unless
' in a non standard format such as 1400Z
Dim R As Range, C As Range
Dim sDelim As String
Dim FileDateFormat As String * 3
Dim i As Long, j As Long, V As Variant
Dim vDateParts As Variant
Dim YR As Long, MN As Long, DY As Long
Dim TM As Double
Dim vRes As Variant 'to hold the results of conversion
Set R = Selection
'Test that selected cell contains a date
If Not IsDate(R(1)) Then
MsgBox "Select a cell containing a date"
Exit Sub
End If
Set R = Intersect(R.EntireColumn, ActiveSheet.UsedRange)
ReDim vRes(1 To R.Rows.Count, 1 To 1)
'Find a "text date" cell to analyze
For Each C In R
With C
If IsDate(.Value) And Not IsNumeric(.Value2) Then
'find delimiter
For i = 1 To Len(.Text)
If Not Mid(.Text, i, 1) Like "#" Then
sDelim = Mid(.Text, i, 1)
Exit For
End If
Next i
'split off any times
V = Split(.Text & " 00:00")
vDateParts = Split(V(0), sDelim)
If vDateParts(0) > 12 Then
FileDateFormat = "DMY"
Exit For
ElseIf vDateParts(1) > 12 Then
FileDateFormat = "MDY"
Exit For
Else
MsgBox "cannot analyze data"
Exit Sub
End If
End If
End With
Next C
If sDelim = "" Then
MsgBox "cannot find problem"
Exit Sub
End If
'Check that analyzed date format different from Windows Regional Settings
Select Case Application.International(xlDateOrder)
Case 0 'MDY
If FileDateFormat = "MDY" Then
MsgBox "File Date Format and Windows Regional Settings match" & vbLf _
& "Look for problem elsewhere"
Exit Sub
End If
Case 1 'DMY
If FileDateFormat = "DMY" Then
MsgBox "File Date Format and Windows Regional Settings match" & vbLf _
& "Look for problem elsewhere"
Exit Sub
End If
End Select
'Process dates
'Could shorten this segment but probably more understandable this way
j = 0
Select Case FileDateFormat
Case "DMY"
For Each C In R
With C
If IsDate(.Value) And IsNumeric(.Value2) Then
'Reverse the day and the month
YR = Year(.Value2)
MN = Day(.Value2)
DY = Month(.Value2)
TM = .Value2 - Int(.Value2)
ElseIf IsDate(.Value) And Not IsNumeric(.Value2) Then
V = Split(.Text & " 00:00") 'remove the time
vDateParts = Split(V(0), sDelim)
YR = vDateParts(2)
MN = vDateParts(1)
DY = vDateParts(0)
TM = TimeValue(V(1))
Else
YR = 0
End If
j = j + 1
If YR = 0 Then
vRes(j, 1) = C.Value
Else
vRes(j, 1) = DateSerial(YR, MN, DY) + TM
End If
End With
Next C
Case "MDY"
For Each C In R
With C
If IsDate(.Value) And IsNumeric(.Value2) Then
'Reverse the day and the month
YR = Year(.Value2)
MN = Day(.Value2)
DY = Month(.Value2)
TM = .Value2 - Int(.Value2)
ElseIf IsDate(.Value) And Not IsNumeric(.Value2) Then
V = Split(.Text & " 00:00") 'remove the time
vDateParts = Split(V(0), sDelim)
YR = vDateParts(2)
MN = vDateParts(0)
DY = vDateParts(1)
TM = TimeValue(V(1))
Else
YR = 0
End If
j = j + 1
If YR = 0 Then
vRes(j, 1) = C.Value
Else
vRes(j, 1) = DateSerial(YR, MN, DY) + TM
End If
End With
Next C
End Select
With R.Offset(0, 1).EntireColumn
Set C = .Find(what:="*", LookIn:=xlFormulas)
If Not C Is Nothing Then .EntireColumn.Insert
End With
R.Offset(0, 1).Value = vRes
End Sub
Disclaimer- my case is specific, and in my case my code works because I know the pattern.
I was looking for an answer everywhere, and the codes I tried were not quite what I was looking for, this is my solution if you are looking for a set of numbers.
In my case, I was looking for 7 digits, starting with digit 1 in a a column with random strings, some string had the number some others didn't.
The number will appear in these three scenarios "1XXXXXX", "PXXXXXXXX", "PXXXXXXXXX"(this has more digits because there is a slash).
Here are the examples of strings:
9797 P/O1743061 465347 Hermann Schatte Earl Lowe
9797 Po 1743071 404440 Claude Gaudette Jose Luis Lopez
9817 1822037 463889 Jean Caron Mickelly Blaise
My Code
Sub getnum()
'i don't use explicit so i didn't declare everything
Dim stlen As String
Dim i As Integer
Dim arra() As String
Dim arran() As String
Orig.AutoFilterMode = False
Call BeginMacro
LastRow = Orig.Cells(Rows.Count, 1).End(xlUp).Row
Orig.Range("J2:J" & LastRow).Clear
'loop though column
For n = 2 To LastRow
celref = Orig.Cells(n, 4).Value
'split string on white spaces
arra() = Split(celref, " ")
'turn string to multiple strings
For counter = LBound(arra) To UBound(arra)
strin = arra(counter)
'remove white spaces from string
storage = Trim(strin)
lenof = Len(storage)
'if string has 9 characthers, check for conditions
If lenof = 9 Then
'position of first and last charachter
somstr = Mid(storage, 1, 1)
somot = Mid(storage, 9, 1)
If somstr = "P" Or somstr = "p" And IsNumeric(somot) = True Then
'removes Po or PO and keeps only 7 digits
storage = Right(storage, 7)
'stores in column J
Orig.Cells(n, 10).Value = storage
End If
ElseIf lenof = 10 Then
somstr = Mid(storage, 1, 1)
somot = Mid(storage, 10, 1)
'other conditions
If somstr = "P" Or somstr = "p" And IsNumeric(somot) = True Then
'removes Po or PO and keeps only 7 digits
storage = Right(storage, 7)
'stores in column J
Orig.Cells(n, 10).Value = storage
End If
End If
'eliminate comma within
arran() = Split(storage, ",")
If Orig.Cells(n, 10).Value <> storage Then
For counter2 = LBound(arran) To UBound(arran)
strin2 = arran(counter2)
storage2 = Trim(strin2)
'final condition if is 7 digits and starts with 1
If IsNumeric(storage2) = True And Len(storage2) = 7 Then
car = Mid(storage2, 1, 1)
If car = 1 Then
'stores in columns J at specific position
Orig.Cells(n, 10).Value = storage2
End If
Else
If isnumeric(orig.cells(n,10).value) =true and _
len(orig.cells(n,10).value = 7 then
orig.cells(n,10).value = orig.cells(n,10).value
else
Orig.Cells(n, 10).Value = "no po# in D"
End If
Next counter2
End If
Next counter
Next n
Call EndMacro
End Sub
you may try this
Option Explicit
Sub getnum()
Dim position As Variant
Dim cell As Range
With Worksheets("Orig") ' change it to your actual sheet name
With Intersect(.UsedRange, Columns("J"))
.Replace what:="P/O", replacement:="P/O ", lookat:=xlPart
For Each cell In .Cells
position = InStr(cell.Text, " 1")
If position > 0 Then cell.Value = Mid(cell.Value, position + 1, 7)
Next
End With
End With
End Sub
This code paste two formulas one in column G and one in column J). The first formula checks for a "P" in the first character of the cell in column 2 and if there is a "P" it extracts the last 7 characters in the string and puts them in column G. The second formula checks if there is not a "P" and if not extracts the last 7 characters in the string and puts them in column J.
Sub Extract()
Dim ws As Worksheet
Dim lRow As Long
Set ws = ThisWorkbook.Sheets("Sheet3")
lRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
ws.Range("G2:G" & lRow).Formula = "=IF(LEFT(B2)=""P"",(RIGHT(B2,7)),"""")"
ws.Range("J2:J" & lRow).Formula = "=IF(LEFT(B2)<>""P"",(RIGHT(B2, 7)),"""")"
End Sub
You may use the RegEx to extract the number in desired format.
Please give this a try...
Function Get10DigitNumber(ByVal Str As String) As String
Dim RE As Object
Set RE = CreateObject("VBScript.RegExp")
With RE
.Global = False
.Pattern = "1\d{6}"
End With
If RE.test(Str) Then
Get10DigitNumber = RE.Execute(Str)(0)
End If
End Function
Then if you want to use this function on the worksheet itself, assuming your string is in A2, try this...
=Get10DigitNumber(A2)
OR
You may use this function in another sub routine/macro like this...
Debug.Print Get10DigitNumber(<pass your string variable here>)
Edited Function:
Function Get10DigitNumber(ByVal Str As String) As String
Dim RE As Object, Matches As Object
Set RE = CreateObject("VBScript.RegExp")
With RE
.Global = False
.Pattern = "[Pp]?\/?[Oo]?(1\d{6})\b"
End With
If RE.test(Str) Then
Set Matches = RE.Execute(Str)
Get10DigitNumber = Matches(0).SubMatches(0)
End If
End Function
And use if as already described above.
After understanding what you were doing, I think this will work. Any feedback would be appreciated.
Dim cell As Range, LRow As Long
LRow = ActiveSheet.Cells(Rows.Count, 4).End(xlUp).Row
For Each cell In Range("D2:D" & LRow)
If cell.Value Like "*Po *" Then
cell.Offset(0, 6).Value = Split(cell.Value, " ")(2)
Else: cell.Offset(0, 6).Value = Split(cell.Value, " ")(1)
End If
Next cell
For Each cell In Range("J2:J" & LRow)
If Len(cell.Value) > 7 Then
cell.Value = Right(cell.Value, 7)
End If
Next
I have a file with 200 rows which have values like this:
ANTWERPEN 3 ABDIJ Abdijstraat 71-73 2020 9:00 18:00 9:00 18:00 9:00 18:00 9:00 18:00 9:00 19:00 9:00 19:00 which I want to have splitted into separate columns.
I want to have 1 column for the part which is in Capitals entirely. In this specific case, that would be:
ANTWERPEN 3 ABDIJ.
And another column for the part that comes after it, until the 4 numeric characters. In this case: Abdijstraat 71-73
I am happy the row values have this distinction to separate the addresses, but I do not know how to do this.
I have had a similar situation for splitting cells at the first numeric character:
text to columns: split at the first number in the value
But now I am looking for a two-fold solution to have in the first column the first part which is entirely in capitals, which represents the city and in the 2nd column I need to have the string which starts with a capital but is then followed by non-capital characters and ends before a 4 characters string of numeric characters.
I would be happy if I could create a vba or excel code/formula which could do this for me, but unfortunately, I can not :-(
So I hope someone can.
edit:
finding some other routines and modifying and testing it, helped me to create this:
Sub doitall()
Dim cell As Range, j As Integer, i As Integer, x As String
Dim str As String
Dim strlen As Integer
Dim k As Integer
Dim l As Integer
Dim y As Integer
' Dim v As Integer
'
'
' For j = 1 To Cells(Rows.Count, 1).End(xlUp).Row
' For Each cell In ActiveSheet.Range(Cells(1, 1), Cells(j, 1))
' For i = 1 To Len(cell)
' x = Mid(cell, i, 1)
' If x = ":" Then Exit For
' Next i
' cell.Offset(0, 1) = Left(cell, i - 8)
' Next cell
' Next j
'geparkeerd
' If l >= 65 And l <= 90 Then
' If v > 1 Then
' m = v - 1
' l = Asc(Mid(Cells(j, 2), m, 1))
' Else
' l = 0
' End If
For j = 1 To Cells(Rows.Count, 2).End(xlUp).Row
For Each cell In ActiveSheet.Range(Cells(1, 2), Cells(j, 2))
For v = 1 To Len(cell)
k = Asc(Mid(cell, v, 1))
If k >= 97 And k <= 122 Then
If v < 1 Then
Exit For
Else: m = v - 1
End If
l = Asc(Mid(cell, m, 1))
If l >= 65 And l <= 90 Then
y = Len(cell) - (v - 1)
cell.Offset(0, 1) = Mid(cell, m, y + 1)
Else
End If
End If
Next v
Next cell
Next j
End Sub
the first part finds the ":" in the cell value and uses all characters on the left from ":" minus 8 as the cell value for the cell in the column next to it.
The second part has to use this 'new' value to separate the city name from the street name. Fortunately, the street name always starts with a capital and is followed by a non-capital.
And fortunately, the city name is completely in capitals which makes it easier to split the value based on Capital followed by non capital.
I focus on the second part now.
what the second part does is check for each cell and each position in the cell if it is non-capital. If it is, it checks if the position before is capital. If it does, it have to use the all characters from the capital as a new value in the cell in the next column.
This works.
But not for this value:
BELLE- ILE "Belle-Ile" Shop 22 -Quai des Vennes 1
the result from that value is only Vennes 1.
but why? v loops from 1 to the length of the cell. But starts at 1 so position 1 is at the left of the cell value. From this routine, the result should actually be Belle-Ile" Shop 22 -Quai des Vennes 1.
Anyone have the explanation for this?
I will adjust it by hand now, but I am just curious to find out why it returns this values.
Solution: v has to check from len(cell) to 1 step -1. After I changed that, It works almost perfectly.
But I still do not understand why. How I read it, is that v starts testing at the last position works towards the first position of the cell value. Like this, in my opinion, the routine would not work I believe. But somehow it does. The key is understanding why v has to be len(cell) to 1 step -1 instead of 1 to len(cell).
I hope someone can explain this to me.
(I will also try the regex solution after I have got to learn something about it).
I am new to regex, but the following works with the input line given above. No doubt a more elegant solution exists, but this might get you going in the right direction. StackOverflow links I found useful in building the regex patterns:
How to match "anything up until this sequence of characters" in a regular expression?
Regex to match mixed case words
Regex to match only uppercase "words" with some exceptions
How to use Regular Expressions (Regex) in Microsoft Excel both in-cell and loops
Function Part1(Myrange As Range) As String
Dim regEx As New RegExp
Dim strPattern As String
Dim strInput As String
strPattern = ".+?(?=[A-Z][a-z]+)"
If strPattern <> "" Then
strInput = Myrange.Value
With regEx
.Global = True
.MultiLine = True
.IgnoreCase = False
.Pattern = strPattern
End With
If regEx.test(strInput) Then
Set matches = regEx.Execute(strInput)
For Each Match In matches
Part1 = Part1 & Match.Value
Next
Else
Part1 = "Not matched"
End If
End If
End Function
Function Part2(Myrange As Range) As String
Dim regEx As New RegExp
Dim strPattern As String
Dim strInput As String
Dim strReplace As String
strPattern = ".+?(?=[A-Z][a-z]+)"
If strPattern <> "" Then
strInput = Myrange.Value
strReplace = ""
With regEx
.Global = True
.MultiLine = True
.IgnoreCase = False
.Pattern = strPattern
End With
If regEx.test(strInput) Then
Part2 = regEx.Replace(strInput, strReplace)
regEx.Pattern = ".+?(?=[0-9]{4})"
Set matches = regEx.Execute(Part2)
For Each Match In matches
Part2 = Match.Value
Next
Else
Part2 = "Not matched"
End If
End If
End Function
This is what I have and what satisfies my 'need':
Sub doitall()
Dim cell As Range, j As Integer, i As Integer, x As String
Dim str As String
Dim strlen As Integer
Dim k As Integer
Dim l As Integer
Dim y As Integer
Dim v As Integer
For j = 1 To Cells(Rows.Count, 1).End(xlUp).Row
For Each cell In ActiveSheet.Range(Cells(1, 1), Cells(j, 1))
For i = 1 To Len(cell)
x = Mid(cell, i, 1)
If x = ":" Then Exit For
Next i
cell.Offset(0, 1) = Left(cell, i - 8)
Next cell
Next j
For j = 1 To Cells(Rows.Count, 2).End(xlUp).Row
For Each cell In ActiveSheet.Range(Cells(1, 2), Cells(j, 2))
For v = Len(cell) To 1 Step -1
k = Asc(Mid(cell, v, 1))
If k >= 97 And k <= 122 Then
If v < 1 Then
Exit For
Else: m = v - 1
End If
l = Asc(Mid(cell, m, 1))
If l >= 65 And l <= 90 Then
y = Len(cell) - (v - 1)
cell.Offset(0, 1) = Mid(cell, m, y + 1)
cell.Offset(0, 2) = Left(cell, (m - 1))
Else
End If
End If
Next v
Next cell
Next j
End Sub
It works almost perfectly. except for some cells that have some other characters in the string which are not covered by this routine.
But I believe that could also be added (check op spaces, double quotes etc.)