Given a string I want to extract some text - excel

Given a list of strings, I want to divide the strings into different columns. The strings does not always comes in the same format, so I cannot use the same approach each time. I am trying to put the LC-XXXXXX in column B, then delete the "s" and put the text after the "s" and between the "^" or the "." (whatever the string contains) into column C
I am running a "for loop" for each string in which is saved as an array and looks something like this:
I have use the split, trim and mid commands but with no success.
With Sheets("TELECOM")
.Range("A14", "I305").ClearContents
For Each objFile In objFolder.Files
On Error Resume Next
If InStr(objFile.Name, "LC-9") > 0 And InStr(objFile.Type, "DWG File") > 0 Then
drwn = objFile.Name
.Cells(r, 2) = Left(drwn, InStr(1, drwn, "s") - 1) 'Get the drawing number and placing it here
values = Array(drwn)
Set re = CreateObject("vbscript.regexp")
pattern = "(s\d+)"
For i = LBound(values) To UBound(values)
.Cells(r, 3) = Replace$(drwn, "s", vbNullString)
Next
r = r + 1
End With
Public Function GetId(ByVal re As Object, ByVal s As String, ByVal pattern As String) As String
With re
.Global = True
.MultiLine = True
.IgnoreCase = False '? True if case insensitive
.pattern = pattern
If .test(s) Then
GetId = .Execute(s)(0).SubMatches(0)
End If
End With
End Function
I would like to take the list of stings and put the LC-XXXXX in column B and the sheet number (numbers between the "s" and the "^" or sometimes the ".dwg" or ".pdf") into a column C
NEW EDIT 04/06/2019
New Edit 04/07/2019
Main Code
Sub GetIssued()
Dim objFSO As Object
Dim objFolder As Object
Dim objFile As Object
Dim openPos As Integer
Dim closePos As Integer
Dim sh As Object
Dim drwn, SheetNum
Set objFSO = CreateObject("scripting.FileSystemObject")
r = 14
fle = ThisWorkbook.Sheets("Header Info").Range("D11") &
"\Design\Substation\CADD\Working\COMM\"
Set objFolder = objFSO.GetFolder(fle)
Set x1Book = ActiveWorkbook 'Using this Activeworkbook
Set sh = x1Book.Sheets("TELECOM") 'Using this particular sheet
With Sheets("TELECOM")
.Range("A14", "I305").ClearContents
For Each objFile In objFolder.Files
On Error Resume Next
If InStr(objFile.Name, "LC-9") > 0 And InStr(objFile.Type, "DWG
File") > 0 Then 'PEDs, Single Line, Cable and Wiring, Jumper and
Interconnection
.Cells(r, 9) = objFile.Name 'Testing Purposes
drwn = Array(.Cells(r, 9).Value)
.Cells(r, 2) = Left(drwn, InStr(1, drwn, "s") - 1) 'Get the
drawing number and placing it here
'-----------------------------------------------------------
'Trying to Insert InstrMacro here
'------------------------------------------------------------
r = r + 1
ElseIf InStr(objFile.Name, "MC-9") > 0 And InStr(objFile.Type, "DWG File") > 0 Then 'Cable List
.Cells(r, 9) = objFile.Name 'Testing Purposes
drwn = .Cells(r, 9).Value
.Cells(r, 2) = Left(drwn, InStr(1, drwn, "s") - 1) 'Get the drawing number and placing it here
'-----------------------------------------------------------
'Trying to Insert InstrMacro here
'------------------------------------------------------------
r = r + 1
ElseIf InStr(objFile.Name, "BMC-") > 0 And InStr(objFile.Type, "Adobe Acrobat Document") > 0 Then 'Bill of Materials
.Cells(r, 9) = objFile.Name 'Testing Purposes
drwn = .Cells(r, 9).Value
.Cells(r, 2) = Left(drwn, InStr(1, drwn, "s") - 1) 'Get the drawing number and placing it here
'-----------------------------------------------------------
'Trying to Insert InstrMacro here
'------------------------------------------------------------
r = r + 1
ElseIf InStr(objFile.Name, "CSR") > 0 And InStr(objFile.Type, "DWG") > 0 Then 'Single Line Diagram
.Cells(r, 9) = objFile.Name 'Testing Purposes
drwn = .Cells(r, 9).Value
.Cells(r, 2) = Left(drwn, InStr(1, drwn, "s") - 1) 'Get the drawing number and placing it here
'---------------------------------------------------------
'Trying to Insert InstrMacro here
'------------------------------------------------------------
r = r + 1
End If
Next
End With
Range("A13:F305").HorizontalAlignment = xlCenter
Range("A1").Select
End Sub
The marco that I have working can be seen here:
Sub InstrMacro()
Dim openPos As Integer
Dim closePos As Integer
Dim drwn, SheetNum
drwn = Range("E9") ' String to search in the sheet aka: the hot seat
'Performing a test to see if this is a new drawing or not
SheetNum = InStr(drwn, "^")
openPos = InStr(drwn, "s") 'True reguardless of the condition of the drawing
If SheetNum = 0 Then 'Assuming it is a new drawing
closePos = InStr(drwn, ".")
SheetNum = Mid(drwn, openPos + 1, closePos - openPos - 1)
Else
If SheetNum > 0 Then 'Assuming is NOT a new drawing
closePos = InStr(drwn, "^")
SheetNum = Mid(drwn, openPos + 1, closePos - openPos - 1)
End If
End If
Range("G20").Value = SheetNum
End Sub
A picture for this macro can be seen here.
I have tried making a separate macro the runs and can get the sheet number, but it seems that excel is just skipping this step and running through the rest of the program
I would like to put the drawing number in column B and the sheet number in sheet number in column c.

A solution with no loops nor regex
Sub FindIt()
Dim strng As String, iPos As Long
strng= "1sa2sb3s4sd5se"
iPos = InStr(strng, "s")
If iPos > 0 And iPos < Len(strng) Then
If InStr("1234567890", Mid(strng, iPos + 1, 1)) > 0 Then
MsgBox "Found s" & Mid(strng, iPos + 1,1) & " at position " & iPos
End If
End If
End Sub
Which can be easily twicked to limit the number of numeric digits following the ā€œsā€ character

If it is s followed by a number/numbers, and this pattern only occurs once, you could use regex.
Option Explicit
Public Sub test()
Dim re As Object, pattern As String, values(), i As Long
values = Array("LC-94773s2^003735377.pdf", "LC-94773s2", "LC-93521s1-A^005241446")
Set re = CreateObject("vbscript.regexp")
pattern = "(s\d+)"
For i = LBound(values) To UBound(values)
Debug.Print Replace$(GetId(re, values(i), pattern), "s",vbNullString)
Next
End Sub
Public Function GetId(ByVal re As Object, ByVal s As String, ByVal pattern As String) As String
With re
.Global = True
.MultiLine = True
.IgnoreCase = False '? True if case insensitive
.pattern = pattern
If .test(s) Then
GetId = .Execute(s)(0).SubMatches(0)
Else
GetId = "No match"
End If
End With
End Function
You can vary this pattern, for example, if want start to be LC-9
Public Sub test()
Dim re As Object, pattern As String, values(), i As Long
values = Array("LC-94773s2^003735377.pdf", "LC-94773s2", "LC-93521s1-A^005241446")
Set re = CreateObject("vbscript.regexp")
pattern = "LC-9(.*)(s\d+)"
For i = LBound(values) To UBound(values)
Debug.Print Replace$(GetId(re, values(i), pattern), "s",vbNullString)
Next
End Sub

To see if a string contains a lower case s followed by a numeral:
Sub sTest()
Dim s As String, i As Long
s = "jkuirelkjs6kbco82yhgjbc"
For i = 0 To 9
If InStr(s, "s" & CStr(i)) > 0 Then
MsgBox "I found s" & i & " at position " & InStr(s, "s" & CStr(i))
Exit Sub
End If
Next i
MsgBox "pattern not found"
End Sub

You could try:
Option Explicit
Sub test()
Dim arr As Variant
Dim i As Long
arr = Array("LC-94773s2^003735377.pdf", "LC-94773s2", "Mar", "LC-93521s1-A^005241446")
For i = LBound(arr) To UBound(arr)
If InStr(1, arr(i), "s") Then
Debug.Print Mid(arr(i), InStr(1, arr(i), "s"), 2)
End If
Next i
End Sub

Related

How to compare between 2 workbooks containing 3 sheets

I try to work on a Project but it seems that it's far from my ability.
I need to Compare 2 workbooks containing 3 sheets ("WireList", "Cumulated BOM" and "BOM"), when I Browse File 1 and File 2 all sheets should compare at the same time and give the result in the format below:
I try a lot of codes but I am still a beginner and I hope if possible someone can help
Thank you very Much
Code Examples 1 : (Just to compare)
Option Explicit
Sub Compare()
'Define Object for Excel Workbooks to Compare
Dim sh As Integer, shName As String
Dim F1_Workbook As Workbook, F2_Workbook As Workbook
Dim iRow As Double, iCol As Double, iRow_Max As Double, iCol_Max As Double
Dim File1_Path As String, File2_Path As String, F1_Data As String, F2_Data As String
'Assign the Workbook File Name along with its Path
File1_Path = ThisWorkbook.Sheets(1).Cells(1, 2)
File2_Path = ThisWorkbook.Sheets(1).Cells(2, 2)
iRow_Max = ThisWorkbook.Sheets(1).Cells(3, 2)
iCol_Max = ThisWorkbook.Sheets(1).Cells(4, 2)
Set F2_Workbook = Workbooks.Open(File2_Path)
Set F1_Workbook = Workbooks.Open(File1_Path)
ThisWorkbook.Sheets(1).Cells(6, 2) = F1_Workbook.Sheets.Count
'With F1_Workbook object, now it is possible to pull any data from it
'Read Data From Each Sheets of Both Excel Files & Compare Data
For sh = 1 To F1_Workbook.Sheets.Count
shName = F1_Workbook.Sheets(sh).Name
ThisWorkbook.Sheets(1).Cells(7 + sh, 1) = shName
ThisWorkbook.Sheets(1).Cells(7 + sh, 2) = "Identical Sheets"
ThisWorkbook.Sheets(1).Cells(7 + sh, 2).Interior.Color = vbGreen
For iRow = 1 To iRow_Max
For iCol = 1 To iCol_Max
F1_Data = F1_Workbook.Sheets(shName).Cells(iRow, iCol)
F2_Data = F2_Workbook.Sheets(shName).Cells(iRow, iCol)
'Compare Data From Excel Sheets & Highlight the Mismatches
If F1_Data <> F2_Data Then
F1_Workbook.Sheets(shName).Cells(iRow, iCol).Interior.Color = vbYellow
ThisWorkbook.Sheets(1).Cells(7 + sh, 2) = "Mismatch Found"
ThisWorkbook.Sheets(1).Cells(7 + sh, 2).Interior.Color = vbYellow
End If
Next iCol
Next iRow
Next sh
'Process Completed
ThisWorkbook.Sheets(1).Activate
MsgBox "Task Completed - Thanks for Visiting OfficeTricks.Com"
End Sub
Code Example 2 :
Option Explicit
Sub test_CompareSheets_Adv()
ActiveWorkbook.Activate
If SheetExists("results") = False Then
Sheets.Add
ActiveSheet.Name = "results"
End If
If CompareSheets_Adv("Sheet3", "Sheet4") = True Then
MsgBox " Completed Successfully!"
Else
MsgBox "Process Failed"
End If
End Sub
Function CompareSheets_Adv(sh1Name$, sheet2name$) As Boolean
Dim vstr As String
Dim vData As Variant
Dim vitm As Variant
Dim vArr As Variant
Dim v()
Dim a As Long
Dim b As Long
Dim c As Long
On Error GoTo CompareSheetsERR
vData = Sheets(sh1Name$).Range("A1:T6817").Value
With CreateObject("Scripting.Dictionary")
.CompareMode = 1
ReDim v(1 To UBound(vData, 2))
For a = 2 To UBound(vData, 1)
For b = 1 To UBound(vData, 2)
vstr = vstr & Chr(2) & vData(a, b)
v(b) = vData(a, b)
Next
.Item(vstr) = v
vstr = ""
Next
vData = Sheets(sheet2name$).Range("A1:T6817").Value
For a = 2 To UBound(vData, 1)
For b = 1 To UBound(vData, 2)
vstr = vstr & Chr(2) & vData(a, b)
v(b) = vData(a, b)
Next
If .exists(vstr) Then
.Item(vstr) = Empty
Else
.Item(vstr) = v
End If
vstr = ""
Next
For Each vitm In .keys
If IsEmpty(.Item(vitm)) Then
.Remove vitm
End If
Next
vArr = .items
c = .Count
End With
With Sheets("Results").Range("a1").Resize(, UBound(vData, 2))
.Cells.Clear
.Value = vData
If c > 0 Then
.Offset(1).Resize(c).Value = Application.Transpose(Application.Transpose(vArr))
End If
End With
CompareSheets_Adv = True
Exit Function
CompareSheetsERR:
CompareSheets_Adv = False
End Function
Function SheetExists(shName As String) As Boolean
With ActiveWorkbook
On Error Resume Next
SheetExists = (.Sheets(shName).Name = shName)
On Error GoTo 0
End With
End Function

Grouping Worksheets with Similar Name Suffix

I'm struggeling to figure out the best way to attack this problem. I'm looking to group worksheet tabs and color code them based on the suffix.
Eg:
Worksheet Names:
ToDo_XY
Done_ZY
ToDo_ZY
Done_XY
Should be:
ToDo_XY
Done_XY
ToDo_ZY
Done_ZY
I know that the worksheet name will end in "non alphanumeric character" in the 3rd last position then two letters and I need to group by the two letters.
I'm not sure if I should be using a collection, or a dictionary or somehow arrays.
Here is what I have so far:
Public Sub GroupLabSheets()
Call GetLabListFromTextFile
Dim ThirdLastCharStr As String, ThirdLastCharStrIsAlphaNumBool As Boolean, PossibleLabStr As String, PossibleLabStrExistsBool As Boolean
For Each ws In ActiveWorkbook.Sheets
ThirdLastCharStr = Mid(ws.Name, Len(ws.Name) - 3, 1)
ThirdLastCharStrIsAlphaNumBool = IsAlphaNumeric(ThirdLastCharStr)
PossibleLabStr = Right(ws.Name, 2)
PossibleLabStrExistsBool = mylabs.Exists(PossibleLabStr)
If ThirdLastCharStrIsAlphaNumBool = False And PossibleLabStrExistsBool = True Then
Debug.Print "Worksheet Name = " & ws.Name & " - Index = " & ws.Index
End If
Next ws
Dim WSArr As Variant
WSArr = Array("ToDo_XY", "Done_XY")
'WSArr.Move Before:=Sheets(1)
Dim i As Long
For i = LBound(WSArr) To UBound(WSArr)
Debug.Print Worksheets(WSArr(i)).Name
Worksheets(WSArr(i)).Tab.Color = WHLabTabColor
Worksheets(WSArr(i)).Move Before:=Sheets(1)
Next i
End Sub
Public Function IsAlphaNumeric(ByVal vInput As Variant) As Boolean
On Error GoTo Error_Handler
Dim oRegEx As Object
If IsNull(vInput) = False Then
Set oRegEx = CreateObject("VBScript.RegExp")
oRegEx.Pattern = "^[a-zA-Z0-9]+$"
IsAlphaNumeric = oRegEx.Test(vInput)
Else
IsAlphaNumeric= True 'Null value returns True, modify as best suits your needs
End If
Error_Handler_Exit:
On Error Resume Next
If Not oRegEx Is Nothing Then Set oRegEx = Nothing
Exit Function
Error_Handler:
Debug.Print "The following error has occured" & vbCrLf & vbCrLf & _
"Error Number: " & err.Number & vbCrLf & _
"Error Source: IsAlphaNumeric" & vbCrLf & _
"Error Description: " & err.Description & _
Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
, vbOKOnly + vbCritical, "An Error has Occured!"
Resume Error_Handler_Exit
End Function
Try this:
Sub ArrangeSheets()
Dim i As Long, wb As Workbook, ws As Worksheet
Dim dict As Object, suffix, colors, col As Collection, n As Long
colors = Array(vbRed, vbYellow, vbGreen, vbBlue) 'colors to be applied (may need to add more...)
Set dict = CreateObject("scripting.dictionary")
Set wb = ThisWorkbook
'collect and group all matched worksheets according to their suffix
For Each ws In wb.Worksheets
If SortIt(ws) Then
suffix = Right(ws.Name, 2)
If Not dict.exists(suffix) Then dict.Add suffix, New Collection
dict(suffix).Add ws
End If
Next ws
'now loop over the groups and move all sheets in a group
' after the first sheet in that group
For i = 0 To dict.Count - 1
Set col = dict.Items()(i)
For n = 1 To col.Count
Set ws = col(n)
ws.Tab.Color = colors(i)
If n > 1 Then ws.Move after:=col(n - 1)
Next n
Next i
End Sub
'is this worksheet a candidate for sorting?
Function SortIt(ws As Worksheet) As Boolean
Dim nm As String
nm = UCase(ws.Name)
If Len(nm) >= 4 Then
SortIt = (Not Mid(nm, Len(nm) - 2, 1) Like "[A-Z0-9]") And _
Right(nm, 2) Like "[A-Z][A-Z]"
End If
End Function
Try this code:
Option Explicit
Sub RearrangeTabs()
Dim a() As String, i As Integer, j As Integer, buf As String, ws As Worksheet
Dim colour As Long
With ActiveWorkbook
ReDim a(1 To .Worksheets.Count, 1 To 2)
i = 1
For Each ws In .Worksheets
buf = ws.Name
' make sort key
a(i, 1) = Right(buf, 2) & IIf(Left(buf, 1) = "T", "A", "Z")
a(i, 2) = buf
i = i + 1
Next
' primitive bubble sort
For i = LBound(a, 1) To UBound(a, 1)
For j = LBound(a, 1) To UBound(a, 1)
If a(i, 1) < a(j, 1) Then
buf = a(i, 1): a(i, 1) = a(j, 1): a(j, 1) = buf
buf = a(i, 2): a(i, 2) = a(j, 2): a(j, 2) = buf
End If
Next j
Next i
colour = 3 'start ColorIndex (built-in set of colors [1..56])
For i = UBound(a, 1) To LBound(a, 1) Step -1
Set ws = .Worksheets(a(i, 2))
ws.Tab.ColorIndex = colour
ws.Move Before:=.Worksheets(1)
' increment ColorIndex for every odd i
If i Mod 2 = 1 Then colour = colour Mod 56 + 1
Next i
End With
End Sub
Before
After

Get data out of a CSV file

There are many hits on google about this but i'm wondering what is the best/fastest way to get some data out of a CSV file?
There are some that load the entire CSV file in excel, some load it in an array. I've seen some people like to do search for a specific word.
Basically I need to retrieve 4 values out of each present CSV file. (start/end time, equipment and substrate) Note that the equipment will repeat itself multiple times inside every file. The other 3 are unique.
Which method is best/fastest?
Here's a small example of the CSV file:
/port_name A
#data 01
#slot_no 2
#m_start 2020/03/26 19:15:27
#m_end 2020/03/26 19:23:21
#u_start ????/??/?? ??:??:??
#u_end ????/??/?? ??:??:??
$result 1 1 -4,-4 2548
<result_info> 1 : Kind :
&no_of_image 3
&i_name 01 S02.tif
~i_info Digital_Zoom 1.0
~i_info Equipment 4000 SERIAL NO. : 31
&i_name 02 S02.tif
~i_info Digital_Zoom 1.0
~i_info Equipment 4000 SERIAL NO. : 31
~CMS_substrate_id 2 "8939-02"
/end_of_file
A quick start of a macro might look like this:
Sub readCSVfile()
Dim textline As String
Dim Filename
Filename = "D:\TEMP\excel\61039635\CSVfile.txt"
Dim row As Integer
Cells(1, 1).Value = "m_start"
Cells(1, 2).Value = "m_end"
Cells(1, 3).Value = "Equipment"
Cells(1, 4).Value = "CMS_substrate_id"
row = 2
Open Filename For Input As #1
Do While Not EOF(1)
Line Input #1, textline
Select Case True
Case InStr(textline, "#m_start") > 0:
Cells(row, 1).Value = mysub(textline, "#m_start")
Case InStr(textline, "#m_end") > 0:
Cells(row, 2).Value = mysub(textline, "#m_end")
Case InStr(textline, "Equipment") > 0:
Cells(row, 3).Value = mysub(textline, "Equipment")
Case InStr(textline, "CMS_substrate_id") > 0:
Cells(row, 4).Value = mysub(textline, "CMS_substrate_id")
row = row + 1
End Select
Loop
Close (1)
End Sub
Function mysub(t As String, s As String) As String
mysub = Trim(Mid(t, InStr(t, s) + Len(s) + 1))
End Function
My answer is similar to #Luuk, but I'm not checking for "Equipment" as it appears in the sample data twice per record. Instead, I am checking for "&i_name 01" and then skipping down a few lines.
Sub sGetData()
On Error GoTo E_Handle
Dim strFile As String
Dim intFile As Integer
Dim strInput As String
Dim lngRow As Long
strFile = "J:\downloads\sample.txt"
intFile = FreeFile
Open strFile For Input As intFile
lngRow = 1
Do
Line Input #intFile, strInput
If InStr(strInput, "#m_start") > 0 Then
lngRow = lngRow + 1
ActiveSheet.Cells(lngRow, 1) = Mid(strInput, 12)
ElseIf InStr(strInput, "#m_end") > 0 Then
ActiveSheet.Cells(lngRow, 2) = Mid(strInput, 12)
ElseIf InStr(strInput, "&i_name 01") > 0 Then
Line Input #intFile, strInput
Line Input #intFile, strInput
ActiveSheet.Cells(lngRow, 3) = Mid(strInput, 41, 4)
ElseIf InStr(strInput, "~CMS_substrate_id") > 0 Then
ActiveSheet.Cells(lngRow, 4) = Mid(strInput, 24)
End If
Loop Until EOF(intFile)
sExit:
On Error Resume Next
Reset
Exit Sub
E_Handle:
MsgBox Err.Description & vbCrLf & vbCrLf & "sGetData", vbOKOnly + vbCritical, "Error: " & Err.Number
Resume sExit
End Sub
As this data file is probably not line terminated with the normal Carriage Return/Line Feed combination that VBA deals with, I've created a new sub that reads the data into an array, split on the end of line character being used (in this case Line Feed) before processing it.
Sub sGetData2()
On Error GoTo E_Handle
Dim strFile As String
Dim intFile As Integer
Dim strInput As String
Dim astrData() As String
Dim lngLoop1 As Long
Dim lngCount As Long
Dim lngRow As Long
strFile = "J:\downloads\sample1.txt"
intFile = FreeFile
Open strFile For Input As intFile
strInput = input(LOF(intFile), intFile)
astrData() = Split(strInput, vbLf)
lngCount = UBound(astrData)
lngRow = 1
For lngLoop1 = 3 To lngCount
If InStr(astrData(lngLoop1), "#m_start") > 0 Then
lngRow = lngRow + 1
ActiveSheet.Cells(lngRow, 1) = Mid(astrData(lngLoop1), 12)
ElseIf InStr(astrData(lngLoop1), "#m_end") > 0 Then
ActiveSheet.Cells(lngRow, 2) = Mid(astrData(lngLoop1), 12)
ElseIf InStr(astrData(lngLoop1), "&i_name 01") > 0 Then
lngLoop1 = lngLoop1 + 2
ActiveSheet.Cells(lngRow, 3) = Mid(astrData(lngLoop1), 41, 4)
ElseIf InStr(astrData(lngLoop1), "~CMS_substrate_id") > 0 Then
ActiveSheet.Cells(lngRow, 4) = Mid(astrData(lngLoop1), 24)
End If
Next lngLoop1
sExit:
On Error Resume Next
Reset
Exit Sub
E_Handle:
MsgBox Err.Description & vbCrLf & vbCrLf & "sGetData2", vbOKOnly + vbCritical, "Error: " & Err.Number
Resume sExit
End Sub
Regards,
Get String from your text file by adodb.stream object.
Extract what you are looking for from the imported string with regexp.
Put the second contents of the submatches of the extracted match collection into an array. Equipment items have two identical contents, so they are increased by two.
The data in the array is transferred to the sheet.
Sub Test()
Dim Ws As Worksheet
Dim Path As String
Dim s As String
Dim pattn(1 To 4) As String
'Dim Match(1 To 4) As MatchCollection
Dim Match(1 To 4) As Object
Dim vR() As Variant
Dim i As Long, n As Long, j As Integer, k As Long
Path = ThisWorkbook.Path & "\regextest.txt" '<~~ Your text file full Path
s = getString(Path) '<~~ get text form your text file
Set Ws = ActiveSheet
'** This is regular Expression
pattn(1) = "(m_start[ ]{1,})(\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2})"
pattn(2) = "(m_end[ ]{1,})(\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2})"
pattn(3) = "(~i_info Equipment[ ]{1,})(\d{1,})"
pattn(4) = "(~CMS_substrate_id[ ]{1,})(\d{1,}[ ]{1,}" & Chr(34) & "\d{1,}-\d{1,}" & Chr(34) & ")"
For i = 1 To 4
Set Match(i) = GetRegEx(s, pattn(i))
Next i
n = Match(1).Count
ReDim vR(1 To n, 1 To 4)
For i = 0 To n - 1
For j = 1 To 4
If j = 3 Then
vR(i + 1, j) = Match(j).Item(k).SubMatches(1)
k = k + 2
Else
vR(i + 1, j) = Match(j).Item(i).SubMatches(1)
End If
Next j
Next i
With Ws
.Cells.Clear
.Range("a1").Resize(1, 4) = Array("m_start", "m_end", "Equipment", "CMS_substrate_id")
.Range("a2").Resize(n, 4) = vR
.Range("a:b").NumberFormatLocal = "yyyy/mm/dd hh:mm:ss"
End With
End Sub
Function GetRegEx(StrInput As String, strPattern As String) As Object
'Dim RegEx As New RegExp
Dim RegEx As Object
'Set RegEx = New RegExp
Set RegEx = CreateObject("VBscript.RegExp")
With RegEx
.Global = True
.IgnoreCase = False
.MultiLine = True
.Pattern = strPattern
End With
If RegEx.Test(StrInput) Then
Set GetRegEx = RegEx.Execute(StrInput)
End If
End Function
Function getString(Path As String)
'Dim objStream As ADODB.Stream
Dim objStream As Object
'Set objStream = New ADODB.Stream
Set objStream = CreateObject("ADODB.Stream")
With objStream
.Charset = "Utf-8"
.Open
.LoadFromFile Path
getString = .ReadText
.Close
End With
End Function
Result image (3 types of data)

VBA code to format an entire column up one row

I am creating a VBA program that will run in the background of my excel file. This VBA program will read fields in from a folder of text files. I have gotten the fields I need read in, I am just having trouble with the formatting. Every value that is read out is put on the next line in the excel file, but it puts it in the correct row, so I need to figure out how to move a whole column up one row once everything is read in. Below I have added my entire program, which was the easiest to see when entering it under the java header(it is VBA code). I have left out my cLines class where my values get stored. The part in the program that writes to the worksheet is where I believe that we will have to insert the formatting.
'Main Module
Option Explicit
'NOTE: Set reference to Microsoft Scripting Runtime
Sub FindInFile()
Dim sBaseFolder As String, sFindText As String, sFindTracNum As String, sFindTrailNum As String, sFindRemarks As String
Dim FD As FileDialog
Dim FSO As FileSystemObject, FIs As Files, FI As File, FO As Folder
Dim TS As TextStream
Dim colL As Collection, TracNum As Collection, TrailNum As Collection, Remarks As Collection, cL As cLines
Dim S As String, strPath As String
Dim I As Long
Dim R As Range
Dim wsRes As Worksheet, rRes As Range, vRes() As Variant
'Set results worksheet and range
Set wsRes = Worksheets("Sheet1")
Set rRes = wsRes.Cells(1, 1)
sFindText = "Driver Name:"
sFindTracNum = "Tractor #:"
sFindTrailNum = "Trailer #:"
sFindRemarks = "Remarks:"
'Specify the folder
strPath = "C:\test\Excel Test"
'Get the Text files in the folder
Set FSO = New FileSystemObject
Set FO = FSO.GetFolder(strPath)
Set FIs = FO.Files
'Collect the information
Set colL = New Collection
Set TracNum = New Collection
Set TrailNum = New Collection
Set Remarks = New Collection
For Each FI In FIs
With FI
If .Name Like "*.txt" Then
I = 0
Set TS = FSO.OpenTextFile(strPath & "\" & .Name, ForReading)
Do Until TS.AtEndOfStream
S = TS.ReadLine
I = I + 1
Set cL = New cLines
If InStr(1, S, sFindText, vbTextCompare) > 0 Then
With cL
.LineText = S
End With
colL.Add cL
ElseIf InStr(1, S, sFindTrailNum, vbTextCompare) > 0 Then
With cL
.TrailNum = S
End With
colL.Add cL
End If
Loop
End If
End With
Next FI
'Write the collection to a VBA array
ReDim vRes(0 To colL.Count, 1 To 6)
'Column Headers
vRes(0, 1) = "Driver Name"
vRes(0, 2) = "Tractor#"
vRes(0, 3) = "Trailer#"
vRes(0, 4) = "Remarks"
vRes(0, 5) = "Next" & vbLf & "Plan"
vRes(0, 6) = "Status" & vbLf & "of" & vbLf & "Repairs"
For I = 1 To colL.Count
With colL(I)
vRes(I, 1) = .LineText
vRes(I, 2) = .TracNum
vRes(I, 3) = .TrailNum
vRes(I, 4) = .Remarks
End With
Next I
'Write to the worksheet
Application.ScreenUpdating = False
Set rRes = rRes.Resize(UBound(vRes, 1) + 1, UBound(vRes, 2))
With rRes
.EntireColumn.Clear
.Value = vRes
With .Rows(1)
.Font.Bold = True
.HorizontalAlignment = xlCenter
End With
With .Columns(3)
'.EntireRow.Cut
'.Offset(-1, 0).EntireRow.Insert shift:=xlDown
End With
.EntireColumn.ColumnWidth = 45
With .EntireRow
.WrapText = True
.VerticalAlignment = xlCenter
.AutoFit
End With
.EntireColumn.AutoFit
'Remove the FindWord
For Each R In rRes.Offset(1).Resize(rRes.Rows.Count - 1).Columns(1).Cells
I = 1
Do
I = InStr(I, R.Text, sFindText, vbTextCompare)
With R.Characters(I, Len(sFindText))
.Delete
End With
I = InStr(I + 1, R.Text, sFindText, vbTextCompare)
Loop Until I = 0
Next R
For Each R In rRes.Offset(1).Resize(rRes.Rows.Count - 1).Columns(3).Cells
I = 1
Do
I = InStr(I, R.Text, sFindTrailNum, vbTextCompare)
With R.Characters(I, Len(sFindTrailNum))
.Delete
End With
I = InStr(I + 1, R.Text, sFindTrailNum, vbTextCompare)
Loop Until I = 0
Next R
End With
Application.ScreenUpdating = True
End Sub'
I figured it out. Here is the updated VBA code:
Option Explicit
'Private Sub Workbook_Open()
'Call FindInFile
'End Sub
'NOTE: Set reference to Microsoft Scripting Runtime
Sub FindInFile()
' Application.OnTime Now + TimeValue("00:01"), "FindInFile"
Dim sBaseFolder As String, sFindText As String, sFindTracNum As String
Dim sFindTrailNum As String, sFindRemarks As String, sFindDefect As String
Dim FD As FileDialog
Dim FSO As FileSystemObject, FIs As Files, FI As File, FO As Folder
Dim TS As TextStream
Dim colL As Collection, TracNum As Collection, TrailNum As Collection
Dim Remarks As Collection, Defect As Collection, cL As cLines
Dim S As String, C As String, strPath As String
Dim I As Long, T As Long, G As Long, H As Long
Dim R As Range
Dim wsRes As Worksheet, rRes As Range, vRes() As Variant
'Set results worksheet and range
Set wsRes = Worksheets("Sheet1")
Set rRes = wsRes.Cells(1, 1)
'Set text you will search for in files
sFindText = "Driver Name:"
sFindTracNum = "Tractor #:"
sFindTrailNum = "Trailer #:"
sFindRemarks = "Remarks:"
sFindDefect = "Defect Found?: No"
'Specify the folder
strPath = "C:\test\Excel Test"
'Get the Text files in the folder
Set FSO = New FileSystemObject
Set FO = FSO.GetFolder(strPath)
Set FIs = FO.Files
'Collect the information
Set colL = New Collection
Set TracNum = New Collection
Set TrailNum = New Collection
Set Remarks = New Collection
Set Defect = New Collection
'Get each field out of the text files
For Each FI In FIs
With FI
If .Name Like "*.txt" Then
I = 0
Set TS = FSO.OpenTextFile(strPath & "\" & .Name, ForReading)
Do Until TS.AtEndOfStream
S = TS.ReadLine
I = I + 1
Set cL = New cLines
If InStr(1, S, sFindDefect, vbTextCompare) > 0 Then
'If (S = "Defect Found?: Yes") Then
'End If
End If
If InStr(1, S, sFindText, vbTextCompare) > 0 Then
With cL
.LineText = S
End With
colL.Add cL
ElseIf InStr(1, S, sFindTrailNum, vbTextCompare) > 0 Then
With cL
.TrailNum = S
End With
TrailNum.Add cL
ElseIf InStr(1, S, sFindRemarks, vbTextCompare) > 0 Then
With cL
.Remarks = S
End With
Remarks.Add cL
End If
Loop
End If
End With
Next FI
'Write the collection to a VBA array
ReDim vRes(0 To colL.Count, 1 To 5)
'Column Headers
vRes(0, 1) = "Driver Name"
vRes(0, 2) = "Tractor#"
vRes(0, 3) = "Trailer#"
vRes(0, 4) = "Remarks"
vRes(0, 5) = "Defect?"
'vRes(0, 6) = "Status" & vbLf & "of" & vbLf & "Repairs"
'Get all of the information on the correct line
For I = 1 To colL.Count
With colL(I)
vRes(I, 1) = .LineText
End With
Next I
For T = 1 To TrailNum.Count
With TrailNum(T)
vRes(T, 3) = .TrailNum
End With
Next T
For G = 1 To Remarks.Count
With Remarks(G)
vRes(G, 4) = .Remarks
End With
Next G
For H = 1 To Defect.Count
With Defect(H)
vRes(H, 5) = .Defect
End With
Next H
'Write to the worksheet
Application.ScreenUpdating = False
Set rRes = rRes.Resize(UBound(vRes, 1) + 1, UBound(vRes, 2))
With rRes
.EntireColumn.Clear
.Value = vRes
With .Rows(1)
.Font.Bold = True
.HorizontalAlignment = xlCenter
.RowHeight = 36
End With
.EntireColumn.ColumnWidth = 45
With .EntireRow
.WrapText = True
.VerticalAlignment = xlCenter
'.AutoFit
End With
.EntireColumn.AutoFit
'Remove the word that is found
For Each R In rRes.Offset(1).Resize(rRes.Rows.Count - 1).Columns(1).Cells
I = 1
Do
I = InStr(I, R.Text, sFindText, vbTextCompare)
With R.Characters(I, Len(sFindText))
.Delete
End With
I = InStr(I + 1, R.Text, sFindText, vbTextCompare)
Loop Until I = 0
Next R
For Each R In rRes.Offset(1).Resize(rRes.Rows.Count - 1).Columns(3).Cells
I = 1
Do
I = InStr(I, R.Text, sFindTrailNum, vbTextCompare)
With R.Characters(I, Len(sFindTrailNum))
.Delete
End With
I = InStr(I + 1, R.Text, sFindTrailNum, vbTextCompare)
Loop Until I = 0
Next R
For Each R In rRes.Offset(1).Resize(rRes.Rows.Count - 1).Columns(4).Cells
I = 1
Do
I = InStr(I, R.Text, sFindRemarks, vbTextCompare)
With R.Characters(I, Len(sFindRemarks))
.Delete
End With
I = InStr(I + 1, R.Text, sFindRemarks, vbTextCompare)
Loop Until I = 0
Next R
End With
Application.ScreenUpdating = True
End Sub

Excel 2007 VBA code to automate extracting and storing numeric values from a string with special characters

I have a string which is in A1 of Sheet1 and it refreshes regularly.
it looks like this -
{"rows":[{"advances":637,"declines":836,"unchanged":76,"total":1549}],"success":"true","results":1}
I want to extract numeric values 637 and 836 and 76 and store it in separate columns. The values keeps on changing, like 637 can be sometimes 1200.
I want a VBA code, not an user defined function to automatically extract the numeric data and store it.
I am using this code, but I am not getting anything. What is wrong?
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$A$1" Then
Dim s As String
Dim fieldNames As Variant
Dim iField As Long
Dim nFields As Long
Dim v As Variant
' specify what you want
fieldNames = Array("advances", "declines", "unchanged")
nFields = UBound(fieldNames) - LBound(fieldNames) + 1
s = [a1].Value ' read in the string
' parse it, put values in a Variant array
ReDim v(1 To 1, 1 To nFields)
For iField = 1 To nFields
s = Mid(s, InStr(s, """" & fieldNames(iField - 1) & """:") _
+ Len(fieldNames(iField - 1)) + 3)
v(1, iField) = Left(s, InStr(s, ",") - 1)
Next iField
' write array to sheet
[b1].Resize(1, nFields).Value = v
End If
Range("=Sheet1!$E$1:$G$1").Copy Destination:=Sheets("Updated").Range("B" & Rows.Count).End(xlUp).Offset(1)
Sheets("Updated").Range("A" & Rows.Count).End(xlUp).Offset(1).Value = Now
End Sub
While I would be tempted to use standard functions for this you could run a VBA UDF like so
to get the first match from A1 (as a number)
=RegexMatches(A1,1)
the second match
=RegexMatches(A1,2)
and so on
The UDF returns "No Match" where no matches are found, or a message "Less than X matches" if you try to extract a match from a position that doesb't exist
Function RegexMatches(strIn As String, LngPos As Long)
Dim objRegex
Dim objRegexMC
Set objRegex = CreateObject("vbscript.regexp")
With objRegex
.Global = True
.Pattern = ":(\d+),"
If .test(strIn) Then
Set objRegexMC = .Execute(strIn)
If objRegexMC.Count >= LngPos Then
RegexMatches = CLng(objRegexMC(LngPos - 1).submatches(0))
Else
RegexMatches = "Less than " & LngPos & " matches"
End If
Else
RegexMatches = "No Match"
End If
End With
End Function
[Update: added sheet event code]
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng1 As Range
Set rng1 = Sheets("Updated").Range("B" & Rows.Count).End(xlUp).Offset(1, 0)
'set row1 as first row if it is blank
If rng1.Row = 2 And rng1.Offset(-1, 0) = vbNullString Then Set rng1 = rng1.Offset(-1, 0)
rng1.Resize(1, 3).Value = Range("B1:D1").Value
rng1.Offset(0, -1).Value = Now
End Sub
You can use an instance of the windows script control to parse the text for you:
Sub Tester()
Dim JSON As String
Dim sc As Object
JSON = "{""rows"":[{""advances"":637,""declines"":836," & _
"""unchanged"":76,""total"":1549}]" & _
",""success"":""true"",""results"":1}"
'JSON = ActiveSheet.Range("A1").Value
Set sc = CreateObject("ScriptControl")
sc.Language = "JScript"
sc.Eval "var o = eval(" & JSON & ")" 'evaluate to an object
Debug.Print "success", sc.Eval("o.success")
Debug.Print "#results", sc.Eval("o.results")
Debug.Print " advances", sc.Eval("o.rows[0].advances")
Debug.Print " declines", sc.Eval("o.rows[0].declines")
Debug.Print " unchanged", sc.Eval("o.rows[0].unchanged")
End Sub
I needed something similar and developed the following code. I have no doubts that it could be made more sophisticated but it provided me with the required result.
Dim cr_ref As String ' Original reference - alpha and numer
Dim new_ref As String ' Resultant numeirc only reference
Dim iAsciiCode As Integer
Dim sCount As Integer ' Length of reference
cr_ref = Trim(Cells(4, 19).Value) ' Get reference from source
sCount = Len(cr_ref)
new_ref = "" ' Start with empty result
For i = 0 To sCount - 1 ' Strip out all except digits
iAsciiCode = Asc(Mid(cr_ref, i + 1, 1)) ' Give me Ascii code
If iAsciiCode >= 48 And iAsciiCode <= 57 Then ' I only want 0-9
new_ref = new_ref & Mid(cr_ref, i + 1, 1) ' Append numeric digit
End If
Next i
' Result is in new_ref
This works:
Dim s As String
Dim fieldNames As Variant
Dim iField As Long
Dim nFields As Long
Dim v As Variant
' specify what you want
fieldNames = Array("advances", "declines", "unchanged")
nFields = UBound(fieldNames) - LBound(fieldNames) + 1
s = [a1].Value ' read in the string
' parse it, put values in a Variant array
ReDim v(1 To 1, 1 To nFields)
For iField = 1 To nFields
s = Mid(s, InStr(s, """" & fieldNames(iField - 1) & """:") _
+ Len(fieldNames(iField - 1)) + 3)
v(1, iField) = Left(s, InStr(s, ",") - 1)
Next iField
' write array to sheet
[b1].Resize(1, nFields).Value = v

Resources