I am reading a .csv database in excel, because I am using an external database.
I dont want to copy anything into the excel application, I either want to read from the database(and maybe change some values), or add to it.
I have a textbox in a userform that should get the value of the last entry in "column" A(A reference number), and add one to it(this is for the next entry in the database).
I want to find the last row in a semicolon split CSV database using excel VBA.
Here is what I have so far:
Dim FilePath As String
FilePath = "L:\database.csv"
Open FilePath For Input As #1
Do While Not EOF(1)
linenumber = linenumber + 1
Line Input #1, Line
arrayOfElements = Split(Line, ";")
elementnumber = 0
testValue = arrayOfElements(0)
If testValue = "L51599" Then
refnr.Text = testValue
Else
'do nothing
End If
Loop
Close #1
Any tips?
Thanks
There are 5 different ways to that here : http://www.thespreadsheetguru.com/blog/2014/7/7/5-different-ways-to-find-the-last-row-or-last-column-using-vba.
Be aware of the fact that CSV files are not excel files and they cannot contain custom VBA functions (Macros). You will have to create your "findLastRow" function in a global template and assign it to a custom button on one of the toolbars/ribbons. this is explained here : https://msdn.microsoft.com/en-us/library/office/ee767705(v=office.14).aspx.
good luck!
Hello and good day to all,
I am trying to import some excel sheets having multiple tabs into the matlab. For this I have written small loop but after many tries and adjustments still cant get all the data into matlab. In the source directory I have 15 excel sheets with 8 tabs each containing data in the 52 x 102 cells. The data is in signed form meaning containing positive and negative values. Here below is the code I was working on and I applied different changes which I found on the internet but no success.
srcdir = 'path to the folder';
srcfiles = dir(fullfile(srcdir, '*.xls'));
for i = 1:length(srcfiles)
[status,sheets] = xlsfinfo(srcfiles(i));
for s = 1:numel(sheets)
[data,titles]=xlsread(srcfiles(i).name,sheets{s});
end
end
Right now I am getting this error " Filename must be a string". I even tried to change it to the char to string but still didn't work.
Only once it worked When I instead of giving the path in the source directory i.e srcdir, gave the name of the file directly in xlsread().
Can anybody help where am I doing mistakes?. Thank you
You likely need to specify the full path to the file using fullfile. Also, in the outer for loop you'll need to use srcfiles(i).name instead of srcfiles(i)
srcdir = 'path to the folder';
srcfiles = dir(fullfile(srcdir, '*.xls'));
for k = 1:numel(srcfiles)
filename = fullfile(srcdir, srcfiles(k).name);
[status,sheets] = xlsfinfo(filename);
for s = 1:numel(sheets)
[data,titles] = xlsread(filename, sheets{s});
end
end
I am writing some code where I import some files under TMX (a form of xml).
I tried various options
a) using the Open FileName For input, but this messes up the character encoding
b) opening the file and copying the data using the msoDialog, but this return an error if the file is too large (which is often the case) and this put the data in an utterly messy manner.
c) opening the file using notepad, but there are the same limitations in so far as copying the entirety of the file into Excel as the previous option.
I am not trying to use a shell function calling onto Wordpad.
My issue right now, is that I need to copy the file line by line to treat its content according to my needs (hopefully without losing the character encoding
Would someone know how to copy every single line from the file opened in WordPad and paste it post treatment (selection of the relevant elements) into Excel?
Thank you
For large files you can use this solution:
Public Sub ImportTMXtoExcel()
Call Application.FileDialog(msoFileDialogOpen).Filters.Clear
Call Application.FileDialog(msoFileDialogOpen).Filters.Add("TMX Files", "*.tmx")
Application.FileDialog(msoFileDialogOpen).Title = "Select a file to import..."
Application.FileDialog(msoFileDialogOpen).AllowMultiSelect = False
intChoice = Application.FileDialog(msoFileDialogOpen).Show
If intChoice <> 0 Then
strFileToImport = Application.FileDialog(msoFileDialogOpen).SelectedItems(1)
Else
Exit Sub
End If
intPointer = FreeFile()
Open strFileToImport For Input Access Read Lock Read As #intPointer
intCounter = 0
Do Until EOF(intPointer)
Line Input #intPointer, strLine
intCounter = intCounter + 1
Worksheets(1).Cells(intCounter + 1, 1).Value2 = strLine
Loop
Close intPointer
End Sub
For other encodings you can use ADO's Stream as described in this solution:
VB6/VBScript change file encoding to ansi
If you have large files which require ADO's Stream then you might want to consider breaking down the large files first as described in this solution:
How to split a large text file into smaller files with equal number of lines?
The following website provides a tool which mimics the Unix command split for Windows in command prompt: https://www.fourmilab.ch/splits/
I have 100 plus different users that will use a certain program that will require different settings in a ini file. I was thinking that excel might be the best way to create these files and write them to a folder in individual files. The data should look like this.
All of this data will need to be in every text file:
UseMct=
UseCellular=
UseKvh=
UseIridium=
UseAurora=
UseSailor=
SailorUnitAddress=
AuroraUnitAddress=
QualcommSerialPort=
MctUnitAddress=
CellularUnitAddress=
KvhSerialPort=
KvhUnitAddress=
IridiumUnitAddress=
IridiumPositionUrl=
HostUrl=
The individual values for each of the following columns will have the required data. so Cell B1 will have the value for the first text file where the above data will be in column A.
UseMct=(value in B1)
UseCellular=(value in B2)
etc, etc.
The next text file will have all of these fields in A1 once again, but with this field mapping.
UseMct=(value in C1)
UseCellular=(value in C2)
etc, etc.
This would loop until the document is completed and would use a certain field as the filenames. Need help! Thanks.
I have looked at the following questions:
Outputting Excel rows to a series of text files
Write each Excel row to new .txt file with ColumnA as file name
You need something like this:
Sub iniCreate()
For iCol = 1 To 3
Open Environ("UserProfile") & "/MyProg" & Range("B1").Offset(0, iCol - 1).Value _
& ".ini" For Output As #1
For jRow = 1 To 16
Print #1, Range("A2").Offset(jRow - 1, 0); Range("A2").Offset(jRow - 1, iCol)
Next jRow
Close #1
Next iCol
End Sub
I used random numbers as data so it looked like this:
V000 V001 V002
UseMct= 0.659099708 0.098897863 0.66830137
UseCellular= 0.081138532 0.064777691 0.919835459
UseKvh= 0.942430093 0.872116053 0.032414535
UseIridium= 0.263586179 0.921751649 0.295967085
UseAurora= 0.867225038 0.094161678 0.11271394
UseSailor= 0.112345073 0.247013614 0.562920243
SailorUnitAddress= 0.641083386 0.630124454 0.430450477
AuroraUnitAddress= 0.133569751 0.431081763 0.620952387
QualcommSerialPort= 0.489904861 0.745152668 0.0371556
MctUnitAddress= 0.390312141 0.643551357 0.621789056
CellularUnitAddress=0.924394826 0.672907813 0.834973453
KvhSerialPort= 0.431335182 0.040557434 0.329205484
KvhUnitAddress= 0.018331225 0.405080112 0.281003
IridiumUnitAddress= 0.530083065 0.428947849 0.781832847
IridiumPositionUrl= 0.473567159 0.428633715 0.00044413
HostUrl= 0.132253798 0.832369002 0.981755331
The V000, V001 etc form part of the file name. E.g. MyProgV000.ini
I use the UserProfile environment variable to select an output folder. You can choose another one if you prefer.
Then the two For Loops just output the data to the file.
I am trying to extract tables from pdf files with vba and export them to excel. If everything works out the way it should, it should go all automatic. The problem is that the table are not standardized.
This is what I have so far.
VBA (Excel) runs XPDF, and converts all .pdf files found in current folder to a text file.
VBA (Excel) reads through each text file line by line.
And the code:
With New Scripting.FileSystemObject
With .OpenTextFile(strFileName, 1, False, 0)
If Not .AtEndOfStream Then .SkipLine
Do Until .AtEndOfStream
//do something
Loop
End With
End With
This all works great. But now I am getting to the issue of extracting the tables from the text files.
What I am trying to do is VBA to find a string e.g. "Year's Income", and then output the data, after it, into columns. (Until the table ends.)
The first part is not very difficult (find a certain string), but how would I go about the second part. The text file will look like this Pastebin. The problem is that the text is not standardized. Thus for example some tables have 3-year columns (2010 2011 2012) and some only two (or 1), some tables have more spaces between the columnn, and some do not include certain rows (such as Capital Asset, net).
I was thinking about doing something like this but not sure how to go about it in VBA.
Find user defined string. eg. "Table 1: Years' Return."
a. Next line find years; if there are two we will need three columns in output (titles +, 2x year), if there are three we will need four (titles +, 3x year).. etc
b. Create title column + column for each year.
When reaching end of line, go to next line
a. Read text -> output to column 1.
b. Recognize spaces (Are spaces > 3?) as start of column 2. Read numbers -> output to column 2.
c. (if column = 3) Recognize spaces as start of column 3. Read numbers -> output to column 3.
d. (if column = 4) Recognize spaces as start of column 4. Read numbers -> output to column 4.
Each line, loop 4.
Next line does not include any numbers - End table. (probably the easiet just a user defined number, after 15 characters no number? end table)
I based my first version on Pdf to excel, but reading online people do not recommend OpenFile but rather FileSystemObject (even though it seems to be a lot slower).
Any pointers to get me started, mainly on step 2?
You have a number of ways to dissect a text file and depending on how complex it is might cause you to lean one way or another. I started this and it got a bit out of hand... enjoy.
Based on the sample you've provided and the additional comments, I noted the following. Some of these may work well for simple files but can get unwieldy with bigger more complex files. Furthermore, there may be slightly more efficient methods or tricks to what I have used here but this will definitely get you going an achieve the desired outcome. Hopefully this makes sense in conjunction with the code provided:
You can use booleans to help you determine what 'section' of the text file you are in. Ie use InStr on the current line to
determine you are in a Table by looking for the text 'Table' and then
once you know you are in the 'Table' section of the file start
looking for the 'Assets' section etc
You can use a few methods to determine the number of years (or columns) you have. The Split function along with a loop will do
the job.
If your files always have constant formatting, even only in certain parts, you can take advantage of this. For example, if you know your
file line will always have a dollar sign in front of the them, then
you know this will define the column widths and you can use this on
subsequent lines of text.
The following code will extract the Assets details from the text file, you can mod it to extract other sections. It should handle multiple rows. Hopefully I've commented it sufficient. Have a look and I'll edit if needs to help out further.
Sub ReadInTextFile()
Dim fs As Scripting.FileSystemObject, fsFile As Scripting.TextStream
Dim sFileName As String, sLine As String, vYears As Variant
Dim iNoColumns As Integer, ii As Integer, iCount As Integer
Dim bIsTable As Boolean, bIsAssets As Boolean, bIsLiabilities As Boolean, bIsNetAssets As Boolean
Set fs = CreateObject("Scripting.FileSystemObject")
sFileName = "G:\Sample.txt"
Set fsFile = fs.OpenTextFile(sFileName, 1, False)
'Loop through the file as you've already done
Do While fsFile.AtEndOfStream <> True
'Determine flag positions in text file
sLine = fsFile.Readline
Debug.Print VBA.Len(sLine)
'Always skip empty lines (including single spaceS)
If VBA.Len(sLine) > 1 Then
'We've found a new table so we can reset the booleans
If VBA.InStr(1, sLine, "Table") > 0 Then
bIsTable = True
bIsAssets = False
bIsNetAssets = False
bIsLiabilities = False
iNoColumns = 0
End If
'Perhaps you want to also have some sort of way to designate that a table has finished. Like so
If VBA.Instr(1, sLine, "Some text that designates the end of the table") Then
bIsTable = False
End If
'If we're in the table section then we want to read in the data
If bIsTable Then
'Check for your different sections. You could make this constant if your text file allowed it.
If VBA.InStr(1, sLine, "Assets") > 0 And VBA.InStr(1, sLine, "Net") = 0 Then bIsAssets = True: bIsLiabilities = False: bIsNetAssets = False
If VBA.InStr(1, sLine, "Liabilities") > 0 Then bIsAssets = False: bIsLiabilities = True: bIsNetAssets = False
If VBA.InStr(1, sLine, "Net Assests") > 0 Then bIsAssets = True: bIsLiabilities = False: bIsNetAssets = True
'If we haven't triggered any of these booleans then we're at the column headings
If Not bIsAssets And Not bIsLiabilities And Not bIsNetAssets And VBA.InStr(1, sLine, "Table") = 0 Then
'Trim the current line to remove leading and trailing spaces then use the split function to determine the number of years
vYears = VBA.Split(VBA.Trim$(sLine), " ")
For ii = LBound(vYears) To UBound(vYears)
If VBA.Len(vYears(ii)) > 0 Then iNoColumns = iNoColumns + 1
Next ii
'Now we can redefine some variables to hold the information (you'll want to redim after you've collected the info)
ReDim sAssets(1 To iNoColumns + 1, 1 To 100) As String
ReDim iColumns(1 To iNoColumns) As Integer
Else
If bIsAssets Then
'Skip the heading line
If Not VBA.Trim$(sLine) = "Assets" Then
'Increment the counter
iCount = iCount + 1
'If iCount reaches it's limit you'll have to redim preseve you sAssets array (I'll leave this to you)
If iCount > 99 Then
'You'll find other posts on stackoverflow to do this
End If
'This will happen on the first row, it'll happen everytime you
'hit a $ sign but you could code to only do so the first time
If VBA.InStr(1, sLine, "$") > 0 Then
iColumns(1) = VBA.InStr(1, sLine, "$")
For ii = 2 To iNoColumns
'We need to start at the next character across
iColumns(ii) = VBA.InStr(iColumns(ii - 1) + 1, sLine, "$")
Next ii
End If
'The first part (the name) is simply up to the $ sign (trimmed of spaces)
sAssets(1, iCount) = VBA.Trim$(VBA.Mid$(sLine, 1, iColumns(1) - 1))
For ii = 2 To iNoColumns
'Then we can loop around for the rest
sAssets(ii, iCount) = VBA.Trim$(VBA.Mid$(sLine, iColumns(ii) + 1, iColumns(ii) - iColumns(ii - 1)))
Next ii
'Now do the last column
If VBA.Len(sLine) > iColumns(iNoColumns) Then
sAssets(iNoColumns + 1, iCount) = VBA.Trim$(VBA.Right$(sLine, VBA.Len(sLine) - iColumns(iNoColumns)))
End If
Else
'Reset the counter
iCount = 0
End If
End If
End If
End If
End If
Loop
'Clean up
fsFile.Close
Set fsFile = Nothing
Set fs = Nothing
End Sub
I cannot examine the sample data as the PasteBin has been removed. Based on what I can glean from the problem description, it seems to me that using Regular Expressions would make parsing the data much easier.
Add a reference to the Scripting Runtime scrrun.dll for the FileSystemObject.
Add a reference to the Microsoft VBScript Regular Expressions 5.5. library for the RegExp object.
Instantiate a RegEx object with
Dim objRE As New RegExp
Set the Pattern property to "(\bd{4}\b){1,3}"
The above pattern should match on lines containing strings like:
2010
2010 2011
2010 2011 2012
The number of spaces between the year strings is irrelevant, as long as there is at least one (since we're not expecting to encounter strings like 201020112012 for example)
Set the Global property to True
The captured groups will be found in the individual Match objects from the MatchCollection returned by the Execute method of the RegEx object objRE. So declare the appropriate objects:
Dim objMatches as MatchCollection
Dim objMatch as Match
Dim intMatchCount 'tells you how many year strings were found, if any
Assuming you've set up a FileSystemObject object and are scanning the text file, reading each line into a variable strLine
First test to see if the current line contains the pattern sought:
If objRE.Test(strLine) Then
'do something
Else
'skip over this line
End If
Set objMatches = objRe.Execute(strLine)
intMatchCount = objMatches.Count
For i = 0 To intMatchCount - 1
'processing code such as writing the years as column headings in Excel
Set objMatch = objMatches(i)
e.g. ActiveCell.Value = objMatch.Value
'subsequent lines beneath the line containing the year strings should
'have the amounts, which may be captured in a similar fashion using an
'additional RegExp object and a Pattern such as "(\b\d+\b){1,3}" for
'whole numbers or "(\b\d+\.\d+\b){1,3}" for floats. For currency, you
'can use "(\b\$\d+\.\d{2}\b){1,3}"
Next i
This is just a rough outline of how I would approach this challenge. I hope there is something in this code outline that will be of help to you.
Another way to do this I have some success with is to use VBA to convert to a .doc or .docx file and then search for and pull tables from the Word file. They can be easily extracted into Excel sheets. The conversion seems to handle tables nicely. Note however that it works on a page by page basis so tables extending over a page end up as separate tables in the word doc.