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)
Related
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
Excel spreadsheet
I have a set of over 10,000 lines of text strings in column A (Input), and I need to get the number (in case there is only one) or a sum of both (in case there are two).
Code
Here is the VBA code I have:
Sub ExtractNumericStrings()
Dim rngTemp As Range
Dim strTemp As String
Dim currNumber1 As Currency
Dim currNumber2 As Currency
Dim lngTemp As Long
Dim lngPos As Long
Dim lngLastRow As Long
With ActiveSheet
lngLastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
For Each rngTemp In .Cells(1, "A").Resize(lngLastRow, 1) ' Set Range to look at
strTemp = rngTemp.Value2 ' Get string value of each cell
lngTemp = Len(strTemp) 'Get length of string
currNumber1 = 0 ' Reset value
currNumber2 = 0 ' Reset value
' Get first number
currNumber1 = fncGetNumericValue(strTemp, 1) ' Strip out first number
' Get second number if exists
' First strip out first number
strTemp = Replace(strTemp, currNumber1, "")
If Len(strTemp) <> 0 Then
currNumber2 = fncGetNumericValue(strTemp, 1)
End If
' now paste to sheet
If currNumber1 <> 0 And currNumber2 <> 0 Then
rngTemp.Offset(0, 1).Value = currNumber1 + currNumber2
rngTemp.Offset(0, 2).Value = "sum of the numbers"
ElseIf currNumber1 <> 0 Then
rngTemp.Offset(0, 1).Value = currNumber1
End If
Next rngTemp
End With
Call MsgBox("Procedure Complete!", vbOKOnly + vbInformation, "Procedure Complete")
End Sub
Private Function fncGetNumericValue(strTemp As String, lngStart As Long) As Currency
Dim varTemp As Variant
Dim lngCount As Long
Dim lngTemp As Long
' Reset
lngCount = 1
lngTemp = 1
varTemp = ""
On Error Resume Next
If IsNumeric(Left(strTemp, lngCount)) Then
Do While IsNumeric(Left(strTemp, lngCount)) = True
varTemp = Left(strTemp, lngCount)
lngCount = lngCount + 1
If lngCount > Len(strTemp) Then
Exit Do
End If
Loop
Else
' First clear non-numerics from string
lngTemp = 1
Do While IsNumeric(Left(strTemp, 1)) = False
lngTemp = lngTemp + 1
strTemp = Mid(strTemp, 2, Len(strTemp) - 1)
If lngTemp > Len(strTemp) Then
Exit Do
End If
Loop
' Then extract second number if exists
If strTemp <> "" Then
Do While IsNumeric(Mid(strTemp, lngCount, 1)) = True
varTemp = Left(strTemp, lngCount)
lngCount = lngCount + 1
If lngCount > Len(strTemp) Then
Exit Do
End If
Loop
End If
End If
' Retrun Value
If IsNumeric(varTemp) Then
fncGetNumericValue = CCur(varTemp)
Else
fncGetNumericValue = 0
End If
End Function
Here is what I'm trying to do:
https://www.youtube.com/watch?v=EjHnJVxuWJA
I have very limited knowledge of VBA, so please excuse me if I ask any stupid question. Running this thing successfully will save me hips of time. thanks!
Something like this:
Private Sub extract_num()
Dim cell as Range
Dim ws as Worksheet: Set ws = Sheets("Sheet1") ' replace Sheet1 with ur sheet name
Dim lr as Long: Set lr = ws.Cells(Rows.Count, 1).End(xlUp).Row
Dim values() As String
Dim i as Byte
Dim temp as Double
For Each cell in ws.Range("A2:A" & lr)
If Not isEmpty(cell) Then
values = Split(cell, " ")
For i = LBound(values) to UBound(values)
values(i) = Replace(values(i), ",", ".")
If isNumeric(values(i)) Then
temp = temp + values(i)
End If
Next i
cell.Offset(0, 2) = temp
temp = 0
End If
Next cell
End Function
This is presuming:
a) Individual words and numbers are always separated by space "123 abc 321"
b) Commas "," are used as an arithmetic floatpoint separator ##,##
Slightly different approach from Rawrplus
Option Explicit
Sub UpdateTotals()
Dim aRawValues As Variant
Dim iLRow&, iRow&, iArr&
Dim dTotal#
With ThisWorkbook.Worksheets("Sheet1") '<-- Change the sheet name to your sheet
iLRow = .Cells(Rows.Count, 1).End(xlUp).Row ' Get row count
For iRow = 1 To iLRow ' Loop through all rows in the sheet
aRawValues = Split(.Range("A" & iRow).Value, " ") ' Create and array of current cell value
For iArr = LBound(aRawValues) To UBound(aRawValues) ' Loop through all values in the array
dTotal = dTotal + ReturnDouble(Replace(aRawValues(iArr), ",", ".")) ' Add the returned double to total
Next
.Range("B" & iRow).Value = dTotal ' Set value in column B
dTotal = 0# ' Reset total
Next
End With
End Sub
Function ReturnDouble(ByVal sTextToConvert As String) As Double
Dim iCount%
Dim sNumbers$, sCurrChr$
sNumbers = ""
For iCount = 1 To Len(sTextToConvert)
sCurrChr = Mid(sTextToConvert, iCount, 1)
If IsNumeric(sCurrChr) Or sCurrChr = "." Then
sNumbers = sNumbers & sCurrChr
End If
Next
If Len(sNumbers) > 0 Then
ReturnDouble = CDbl(sNumbers)
Else
ReturnDouble = 0#
End If
End Function
I have some VBA code that loops through all the cells in Column E , it then looks for a match in the text file and enters the first word from the line of text that is matched in the txt file. This works , but when I loop through over 10000 rows , it takes 3 hours to complete.
Just checking if there was a more efficient way of doing this. To speed up the process. Any help would be much appreciated
Sub SearchTextFile()
Dim x
Dim hex, reg As String
Dim strsearch As String
x = Sheet9.Range("Q1").Value
Dim hexa As String
Const strFileName = "T:\Hex\Hex_Codes.txt"
hex = Sheet9.Range("P1").Value
reg = Sheet1.Range("E" & x).Value
If Right(reg, 1) = "-" Then GoTo err
strsearch = hex
Dim strLine As String
Dim f As Integer
Dim lngLine As Long
Dim blnFound As Boolean
f = FreeFile
Open strFileName For Input As #f
Do While Not EOF(f)
lngLine = lngLine + 1
Line Input #f, strLine
If InStr(1, strLine, strsearch, vbBinaryCompare) > 0 Then
Text = Text & strLine
On Error GoTo err
Sheet1.Range("L" & x).Value = Format(Split(Text, ",")(0), "#")
blnFound = True
Exit Do
End If
Loop
Close #f
If Not blnFound Then
End If
err:
End Sub
Sub searchReg()
Application.ScreenUpdating = False
Application.EnableEvents = False
Dim lr1
lr1 = Sheet1.Range("A" & Rows.Count).End(xlUp).Row
Dim y
For y = 2 To lr1
Sheet9.Range("P1").Value = Sheet1.Range("E" & y).Value
Sheet9.Range("Q1").Value = y
Call SearchTextFile
Next y
Call verify_text_formulas
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
I've used a single static read from the text file to avoid repetitive open.read/close calls.
I've removed the use of Sheet8 as a holding/transfer place for values by passing the important and necessary values into the SearchTextFile helper as parameters/arguments.
You provided no information on verify_text_formulas so it is currently commented out.
hex and reg seemed to be the same thing; hexa was never used; text was never declared and seemed redundant. I've reduced the use of extraneous variables.
Option Explicit
Const cFileName As String = "T:\Hex\Hex_Codes.txt"
Sub SearchTextFile(Optional hex As String, _
Optional ln As Long = -1, _
Optional closeOff As Boolean = False)
Static txt As String
Dim ff As Integer, p As Long, ps As Long, str As String
Dim blnFound As Boolean
If txt = vbNullString Then
'Debug.Print "new read"
ff = FreeFile(1)
Open cFileName For Binary As #ff
txt = Space$(LOF(ff))
Get #ff, , txt
Close #ff
txt = vbLf & txt
End If
If closeOff Then
'Debug.Print "closed"
txt = vbNullString
Else
p = InStr(1, txt, hex, vbBinaryCompare)
If p > 0 Then
ps = InStrRev(txt, vbLf, p, vbBinaryCompare)
str = Chr(39) & Split(Mid(txt, ps + 1, p - ps + 1), ",")(0)
Sheet1.Cells(ln, "L") = str
blnFound = True
End If
End If
If Not blnFound Then
End If
err:
End Sub
Sub searchReg()
Dim y As Long
debug.print timer
'Application.ScreenUpdating = False
'Application.EnableEvents = False
For y = 2 To Sheet1.Range("A" & Rows.Count).End(xlUp).Row
SearchTextFile hex:=Sheet1.Cells(y, "E").Value, ln:=y
Next y
SearchTextFile closeOff:=True
'Call verify_text_formulas
Application.ScreenUpdating = True
Application.EnableEvents = True
debug.print timer
End Sub
Post back some timer counts for various record sets if you have a chance. This was tested on a small (30 rows) .TXT file but I would be interested in the time it takes to process larger files.
I want to import multiple csv files at the bottom of an existing table. However, when importing the files, it always excludes the first row of the list of each file. The first row of the list differs from the first row of the spreadsheet because in between there are other rows that are not needed (e.g. titles, empty rows...). Resuming: if I upload 5 files, it miss the first desired row of each of the 5 files.
This is the code:
Private Sub Import_auction_offers_Click()
Dim strSourcePath As String
Dim strFile As String
Dim Cnt As Long
'Change the path to the source folder accordingly
strSourcePath = "C:\Users\L18944\Desktop\example"
If Right(strSourcePath, 1) <> "\" Then strSourcePath = strSourcePath & "\"
strFile = Dir(strSourcePath & "*.csv")
Do While Len(strFile) > 0
Cnt = Cnt + 1
Open strSourcePath & strFile For Input As #1
If Range("F2").Value <> "" Then
Range("F1").End(xlDown).offset(1, 0).Select
Else:
Range("F1:F" & Range("F" & Rows.Count).End(xlUp).Row).offset(1, 0).Select
End If
currentRow = 0
rowNumber = 0
'EOF(1) checks for the end of a file
Do Until EOF(1)
Line Input #1, lineFromFile
fileStr = Split(lineFromFile, vbLf)
Dim item As Variant
For Each item In fileStr
'For item = LBound(fileStr) To UBound(fileStr)
lineitems = Split(item, ";")
'Debug.Print (item)
If rowNumber = 1 Then
startDate = lineitems(6)
End If
If rowNumber > 3 And item <> "" Then
If Not doesOfferExist(CStr(lineitems(2))) Then
ActiveCell.offset(currentRow, 0) = startDate
ActiveCell.offset(currentRow, 1) = lineitems(4)
ActiveCell.offset(currentRow, 2) = lineitems(3)
ActiveCell.offset(currentRow, 3) = CDbl(lineitems(6))
ActiveCell.offset(currentRow, 4) = CDbl(lineitems(7))
ActiveCell.offset(currentRow, 5) = lineitems(8)
ActiveCell.offset(currentRow, 6) = lineitems(1)
ActiveCell.offset(currentRow, 7) = lineitems(2)
ActiveCell.offset(currentRow, 8) = "New"
currentRow = currentRow + 1
End If
End If
rowNumber = rowNumber + 1
Next item
Loop
Close #1
Name strSourcePath & strFile As strSourcePath & strFile
strFile = Dir
Loop
Application.ScreenUpdating = True
If Cnt = 0 Then _
MsgBox "No CSV files were found...", vbExclamation
End Sub
Does anyone understand why it miss the first line of each imported list?
Thank you in advance
I didn't go through your ImportAuctionOffers code, but I'm assuming you are finding the new starting row for each file.
This code will let you pick your files (and set your initial directory). Then loop through all the selected items, calling your ImportAuctionOffers procedure for each file.
Sub test()
Dim oFileDialog As FileDialog
Set oFileDialog = Application.FileDialog(msoFileDialogFilePicker)
oFileDialog.AllowMultiSelect = True
oFileDialog.InitialFileName = "C:\Temp" ' can set your default directory here
oFileDialog.Show
Dim iCount As Integer
For iCount = 1 To oFileDialog.SelectedItems.Count
Call ImportAuctionOffers(oFileDialog.SelectedItems(iCount))
Next
End Sub
Update:
For your second issue: Not reading the first data line is likely due to the if statements with RowNumber.
rowNumber=0
Do ...
if RowNumber = 1 Then ...
if RowNumber > 3 ...
RowNumber = RowNumber + 1
loop
Your code is not going to enter either of your if statements when RowNumber equals 0, 2, or 3. You probably just need to change your > 3 to either > 2, or >= 3.
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