trim a string / file path in vba? - string

I have the following code which produces a list of excel file paths and email addresses contained in those workbooks.
Code:
Option Explicit
Sub SO()
'clear the existing list here -- not implemented
'...
Range("G17:G" & ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row).ClearContents
Range("V17:V" & ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row).ClearContents
Range("AD17:AD" & ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row).ClearContents
Dim pathsEmails As New Dictionary
Dim app As New Excel.Application
Dim fso As New FileSystemObject
Dim weekFolder As Folder
'replace 1 with either the name or the index of the worksheet which holds the week folder path
'replace B4 with the address of the cell which holds the week folder path
Set weekFolder = fso.GetFolder(Worksheets(1).Range("I8").Value)
Dim supplierFolder As Folder, fle As file
For Each supplierFolder In weekFolder.SubFolders
For Each fle In supplierFolder.files
'test whether this is an Excel file
If fle.Type Like "*Excel*" Then
'open the workbook, read and save the email, and close the workbook
Dim book As Workbook
On Error Resume Next
Set book = app.Workbooks.Open(fle.path, , True)
pathsEmails(fle.path) = book.Worksheets(1).Range("C15").Value
book.Close False
End If
Next
Next
app.Quit
'copy the paths and emails to the worksheet
'(as above) replace 1 with either the name or the index of the worksheet which holds the week folder path
'paths are pasted in starting at cell B6, downwards
'emails are pasted in starting at cell C6, downwards
Worksheets(1).Range("G17").Resize(UBound(pathsEmails.Keys) + 1, 1).Value = WorksheetFunction.Transpose(pathsEmails.Keys)
Worksheets(1).Range("V17").Resize(UBound(pathsEmails.Items) + 1, 1).Value = WorksheetFunction.Transpose(pathsEmails.Items)
'Clear empty cells
On Error Resume Next
Range("V17:V" & ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row).SpecialCells(xlBlanks).EntireRow.Delete
End Sub
This produces a result like so:
G:\folder1\file.xls email#email.com
How can i trim my file path to produce just the following:
file.xls email#email.com
I have tried
replace(pathsEmails(fle.path), "G:\folder1\" , "")
But this doesn't work. Please can someone show me where i am going wrong?
Edit:
Sometimes i have more than one email address in the cell C15.
email#email.com / tom#email.com
So this causes the emails in the workbook to be listed like so:
email#email.com / tom#email.com
Is there anyway i can replace the / and replace it with a , (to make it email friendly)

Using files' names as keys, you should have the desired output :
(if not, try : pathsEmails(Replace(fle.Path,weekFolder.Path,vbNullString)) = book.Worksheets(1).Range("C15").Value)
Option Explicit
Sub SO()
'clear the existing list here -- not implemented
'...
Dim wS As Worksheet
Dim LastRow As Long
Dim i as Long
Set wS = ThisWorkbook.ActiveSheet
With wS
LastRow = .Range("G" & .Rows.Count).End(xlUp).Row
.Range("G17:G" & LastRow).ClearContents
.Range("V17:V" & LastRow).ClearContents
.Range("AD17:AD" & LastRow).ClearContents
End With
Dim pathsEmails As New Dictionary
Dim app As New Excel.Application
Dim fso As New FileSystemObject
Dim weekFolder As Folder
Dim supplierFolder As Folder
Dim fle As File
'replace 1 with either the name or the index of the worksheet which holds the week folder path
'replace B4 with the address of the cell which holds the week folder path
Set weekFolder = fso.GetFolder(wS.Range("I8").Value)
For Each supplierFolder In weekFolder.SubFolders
For Each fle In supplierFolder.Files
'test whether this is an Excel file
If fle.Type Like "*Excel*" Then
'open the workbook, read and save the email, and close the workbook
Dim book As Workbook
On Error Resume Next
Set book = app.Workbooks.Open(fle.Path, , True)
pathsEmails(fle.Name) = book.Worksheets(1).Range("C15").Value
book.Close False
End If
Next fle
Next supplierFolder
app.Quit
'copy the paths and emails to the worksheet
'(as above) replace 1 with either the name or the index of the worksheet which holds the week folder path
'paths are pasted in starting at cell B6, downwards
'emails are pasted in starting at cell C6, downwards
With wS
.Range("G17").Resize(UBound(pathsEmails.Keys) + 1, 1).Value = WorksheetFunction.Transpose(pathsEmails.Keys)
.Range("V17").Resize(UBound(pathsEmails.Items) + 1, 1).Value = WorksheetFunction.Transpose(pathsEmails.Items)
'Clear empty cells
On Error Resume Next
LastRow = .Range("G" & .Rows.Count).End(xlUp).Row
For i = 17 To LastRow
.Range("V" & i)=Replace(.Range("V" & i),"/",",")
Next i
.Range("V17:V" & LastRow).SpecialCells(xlBlanks).EntireRow.Delete
End With
End Sub

Why not use something like mid(fle.path,11,len(fle.path) - 11)?

Related

Iteratively break out a data file to a template file and save as a new file for every 5,000 rows

I am trying to break out a data file by 5,000 rows due to limitation with a tool. I have a template file that has multiple sheets (I only have to update data on the first sheet titled 'Service Template', but I need all tabs present on the newly created files). The tool requires the template file to be used so I have to use that file instead of copying the data to a completely new file. I am also attempting to do this on a Mac, but can use virtual machine if absolutely necessary.
The data file and the template file both start on row 2 as both files have headers.
I have the below code that I have been trying to build out but it is still not working and I am stuck.
Data file sheet = 'Sheet1' and Template File Sheet = 'Service Template'
Sub test()
Dim lastRow As Long, myRow As Long, myBook As Workbook
ActiveSheet.Name = "Sheet1"
lastRow = ThisWorkbook.Sheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row
For myRow = 1 To lastRow Step 5000
Set myBook = Workbooks.Open("/Users/Downloads/Test/TemplateFile.xlsx")
ThisWorkbook.Sheets("Sheet1").Rows(myRow & ":" & myRow + 4999).EntireRow.Copy myBook.Sheets("Sheet1").Range("A2")
Application.DisplayAlerts = False
myBook.SaveAs Filename:="\Users\Downloads\Test\" & myBook.Name
Application.DisplayAlerts = False
myBook.Close
Next myRow
End Sub
I am looking to transfer 5000 rows (starting row2) from the data file to the template file (starting row2) save as a new file and then keep doing the same process until all of the rows are complete.
Try something like this:
Sub test()
Const BLOCK_SIZE As Long = 5000
Dim wsSrc As Worksheet, myBook As Workbook, rngCopy As Range
Set wsSrc = ActiveSheet 'or some other specific sheet
Set rngCopy = wsSrc.Rows(2).Resize(BLOCK_SIZE)
Do While Application.CountA(rngCopy) > 0 'loop while range has content
With Workbooks.Open("/Users/Downloads/Test/TemplateFile.xlsx")
rngCopy.Copy .Worksheets("Sheet1").Range("A2")
.SaveAs "\Users\Downloads\Test\" & "R" & rngCopy.Row & "_" & .Name
.Close SaveChanges:=True
End With
Set rngCopy = rngCopy.Offset(BLOCK_SIZE) 'next block down
Loop
End Sub

Copy columns to new workbook and save as csv

I'm trying to:
Copy data (columns A and B) from one workbook (data.xlsx).
Paste into a new workbook (as values).
Save as CSV with a filename taken from column A in a third workbook (URLs.xlsx).
Process to repeat, taking the same data (which is randomised every time it is pasted) from data.xlsx and pasted into a new CSV - there are 200 rows in URLs.xlsx and so we should end up with 200 files.
I've read lots of topics, here are two I found:
Excel VBA Copy a Range into a New Workbook
https://www.excelcampus.com/vba/copy-paste-another-workbook/
What I've tried
Copying code and replacing the relevant components from various different articles across the web. Some of them work, but when I add the missing bits, I run into errors I don't understand.
Well here is an example avoiding copy pasting in new workbooks:
Expected input like:
Data.xlsx range A1:B200 with RANDBETWEEN() function:
URLs.xlsx range A1:A200 with some URL like so:
Run this code (will take approximately 1 second on my machine, tested with timer):
Dim wbData As Workbook, WBurls As Workbook
Dim CSVFileDir As String, CSVVal As String
Dim A As Long, X As Long, Y As Long, Z As Long
Option Explicit
Sub Transfer2CSV()
Set wbData = Workbooks("data.xlsx") 'Make sure it is open upon running macro
Set WBurls = Workbooks("URLs.xlsx") 'Make sure it is open upon running macro
For X = 1 To 200 'Looping through the 200 rows of WBurls
CSVFileDir = "C:\YourDrive\" & WBurls.Sheets(1).Cells(X, 1).Value & ".csv"
CSVVal = ""
A = FreeFile
Open CSVFileDir For Output As #A
With wbData.Sheets(1).Range("A1:B200") ' or whichever range you using here
.Calculate 'Randomize your range again
For Y = 1 To 200 'or however many rows you have in column A and B.
For Z = 1 To 2
CSVVal = CSVVal & .Cells(Y, Z).Value & ","
Next Z
Print #A, Left(CSVVal, Len(CSVVal) - 2)
CSVVal = ""
Next Y
End With
Close #A
Next X
End Sub
Output:
With each file looking like:
This should work. Make sure your data and URLS workbooks are open.
Sub Macro1()
Dim wsData As Worksheet, wsUrl As Worksheet, wbNew as Workbook
Dim CSVDir as String, rngU As Range
Set wsData = Workbooks("data.xlsx").Worksheets(1)
Set wsUrl = Workbooks("URLs.xlsx").Worksheets(1)
Set rngU = wsUrl.Range("A1", wsUrl.Range("A" & wsUrl.Rows.Count).End(xlUp))
CSVDir = "C:\Users\thomas.mcerlean\Desktop\Work\" 'you gave this as your dir
Set wbNew = Workbooks.Add
For Each cell In rngU
wsData.Range("A1", wsData.Range("B" & wsData.Rows.Count).End(xlUp)).Copy Destination:= wbNew.Worksheets(1).Range("A1")
wbNew.SaveAs Filename:= CSVDir & cell.Value & ".csv", FileFormat:=xlCSV
Next cell
wbNew.Close SaveChanges:=False
End Sub

Excel VBA: Copy data from multiple passwordprotected workbooks in a folder into one worksheet in another workboo

I have written a code that opens a password protected workbook in a folder, copy some values out of it and paste the values in active woorkbook. This works fine.
My problem is that I have 16 password protected files in this folder, and I need a loop that does the same thing with every file. Below you can find the code, and I think all my problems should be properly explained with comments inside the code. Please ask if anything is unclear. In advance, thanks for any help!
Code:
Sub Bengt()
Dim sPath As String
Dim vFolder As Variant
Dim sFile As String
Dim sDataRange As String
Dim mydata As String
Dim wb As Workbook
Dim WBookOther As Workbook
Dim myArray As Variant '<<does the list of passwords have to be array?
sPath = ThisWorkbook.Path & Application.PathSeparator
sDataRange = "Budsjett_resultat'!E2" '<<every file I want to open has data in this sheet and range
sFile = "BENGT.xlsm" '<< how to make sFile be every file in folder?
' here I want a loop that opens every woorkbook in the folder M::\SALG\2016\Budsjett\
Set WBookOther = Workbooks.Open(sPath & sFile, Password:="bengt123")
' all passwords starts with filename + three numbers after as you can see
' here I want to make excel find the password out of a list of passwords in range B100:B116
mydata = "='" & sPath & "[" & sFile & "]" & sDataRange
'mydata = "='M:\SALG\2016\Budsjett\Bengt.xlsmBudsjett_resultat'!E2:E54" '<< change as required
'link to worksheet
With ThisWorkbook.Worksheets(1).Range("T2:T54")
'in this case I want the loop to find "BENGT"(which is the filename) in cell T1, and paste the values in range T2:T54.
'For the other files, I want the loop to find the filename (of the file it opened) in row 1,
'and paste the values in range ?2-?54 at the column with the same name as the filename
.Formula = mydata
.Value = .Value
WBookOther.Close SaveChanges:=False
End With
End Sub
For the password array I have tried following code:
Sub passord()
Dim myArray As Variant
myArray = ThisWorkbook.Worksheets(1).Range("B100:B116")
On Error Resume Next 'turn error reporting off
For i = LBound(myArray, 1) To UBound(myArray, 1)
Set wb = Workbooks.Open("M:\SALG\2016\Budsjett\BENGT.xlsm", Password:=myArray(i, 1))
If Not wb Is Nothing Then bOpen = True: Exit For
Next i
End Sub
I have tried to implement the last sub into the first sub, but I can't figure out how to make it work.

Subscript out of range run time error 9

I am creating a function that reads column titles from two excel files and then place those column titles in checkboxes so the user can check which columns he will work with. It works when I do it with one file but when I modify it to work with two files I get the "run time error 9: Subscript out of range" and highlights the line => Set wks2 = ActiveWorkbook.Worksheets(SheetName2).
Even with this error message still works for the first file but it does not work with the second file. Can anybody help me to find the reason of this error message? Thank you very much in advance.
Function CallFunction(SheetName1 As Variant, SheetName2 As Variant) As Long
' This is a function used to retrieve column titles and place them as checkboxes in a listBox
Dim jTitles(200) As String
Dim sTitles(200) As String
Dim titless As Integer
Dim titlesj As Integer
Dim wks1 As Worksheet
Dim wks2 As Worksheet
Dim Item(200) As String
SPathName = Range("F18").Value
SFilename = Range("F19").Value
JPathName = Range("F22").Value
JFilename = Range("F23").Value
Workbooks.Open Filename:=SPathName & "\" & SFilename
Workbooks.Open Filename:=JPathName & "\" & JFilename
Set wks1 = ActiveWorkbook.Worksheets(SheetName1)
For j = 1 To 199
If Trim(wks1.Cells(4, j).Value) = "" Then
titlesj = j - 1
Exit For
End If
jTitles(j - 1) = wks1.Cells(4, j).Value
Next
j = 1
' Add column titles from files into the listbox as checkboxes
For j = 0 To titlesj
Sheet1.ListBox1.AddItem jTitles(j)
Sheet1.ListBox3.AddItem jTitles(j)
Next
Set wks2 = ActiveWorkbook.Worksheets(SheetName2) ' <=== HERE POPS THE ERROR MESSAGE
For s = 1 To 199
If Trim(wks2.Cells(1, s).Value) = "" Then
titless = s - 1
Exit For
End If
sTitles(s - 1) = wks2.Cells(1, j).Value
Next
s = 1
For s = 0 To titless
Sheet1.ListBox2.AddItem sTitles(s)
Sheet1.ListBox4.AddItem sTitles(s)
Next
Workbooks(JFilename).Close
' Workbooks(SFilename).Close
End Function
Subscript out of Range error arises in these circumstances when the specified sheetname does not exist in that workbooks Worksheets collection.
I notice you have two open workbooks specified by:
Workbooks.Open Filename:=SPathName & "\" & SFilename
Workbooks.Open Filename:=JPathName & "\" & JFilename
However, both of your worksheet assignments refer only to the ActiveWorkbook.
The cause of the error is certainly that SheetName2 does not exist in the ActiveWorkbok (which is specified by JFilename)
Especially when working with multiple books or worksheets, it is always preferable to avoid using Activate/Select methods-- otherwise you need to keep track of which workbook/worksheet/etc. is "Active", and that makes for spaghetti code and lots of unnecessary calls to the .Activate method.
I know that SheetName1 exists in JFilename, and I am assuming that SheetName2 exist in the workbook SFileName.
Instead, define two Workbook variables:
Dim wb1 as Workbook
Dim wb2 as Workbook
Assign the results of the Workbooks.Open method to these workbooks:
Set wb2 = Workbooks.Open(Filename:=SPathName & "\" & SFilename)
Set wb1 = Workbooks.Open(Filename:=JPathName & "\" & JFilename)
Now, wb1 is the "Active" workbook, so with the worksheet assignments:
Set wks1 = wb1.Worksheets(SheetName1)
And later for the Sheetname2:
Set wks2 = wb2.Worksheets(Sheetname2)
Otherwise, there is a typo in your worksheet names or the string parameters you're sending to this function. Doublecheck/debug that the value of SheetName2 is correct and that it exists.

Copy Range, Paste into New Workbook, Multiple Files, Delete Blank Rows

First time poster here. I've been reading tutorials/guides all day and made a lot of strides, but am having a tough time figuring out how to write a macro that does what I want to do.
I get around 100 time sheets per week that are then copied and imported into an accounting software. The sheets are all based off of a template, are in separate workbooks, and have a worksheet titled "Pre Import Time Card" within them. I copy the values from each book's pre import worksheet into a new file and upload them to our accounting software as a batch.
I want to have a macro open each file automatically, copy the range A1:I151 on each workbook, and then paste the values into a new worksheet. Because of the import templates design, this inevitably leads to many blank rows within the specified range. I would like to delete any blank rows as a final step.
UPDATE: I HAVE COPIED THE CODE TO REFLECT WHAT I CURRENTLY HAVE.Also a list of new problems is below.
pasting to next unused row is not working
I need to figure out how to kill the old file / not have it enter the same file twice.
I would like to suppress the "Privacy warning on VBA / Active X controls" dialog that comes up at each save.
It's not currently copying correctly. I'm getting a bug at the rDest.Resize line.
Object variable or With Block Variable not set.
I had it running when using file names in an array, but decided that was unnecessary and to use a For.. Each loop.
Sub CopySourceValuesToDestination()
Dim wbDest As Workbook
Dim wbSource As Workbook
Dim sDestPath As String
Dim sSourcePath As String
Dim aFile As String
Dim shDest As Worksheet
Dim rDest As Range
Dim i As Long
Dim TSSize As Object
Dim objFso As Object 'New FileSystemObject
Dim objFolder As Object 'Folder
Dim objFile As Object 'File
Set objFso = CreateObject("Scripting.FileSystemObject")
sDestPath = "Z:\Dropbox\My Documents\TimeSheets\Processed\"
sSourcePath = "Z:\Dropbox\My Documents\TimeSheets\Copying\"
'Open the destination workbook at put the destination sheet in a variable
Set wbDest = Workbooks.Open(sDestPath & "Destination.xlsm")
Set shDest = wbDest.Sheets(1)
Set objFolder = objFso.GetFolder(sSourcePath)
For Each objFile In objFolder.Files
aFile = objFile.Name
Set objWb = Workbooks.Open(sSourcePath & aFile)
'find the next cell in col A
Set rDest = shDest.Cells(xlLastRow + 1, 1)
'write the values from source into destination
TSSize = wbSource.Sheets(4).Range("A1").End(xlDown).Row
rDest.Resize(TSSize, 9).Value = wbSource.Sheets(4).Range("A1:I" & TSSize).Value
wbSource.Close False
wbDest.SaveAs sDestPath & "Destination.xlsm"
wbDest.Close
Kill sSourcePath & wbSource
Next
End Sub
Function xlLastRow(Optional WorksheetName As String) As Long
' find the last populated row in a worksheet
If WorksheetName = vbNullString Then
WorksheetName = ActiveSheet.Name
End If
With Worksheets(1)
xlLastRow = .Cells.Find("*", .Cells(1), xlFormulas, _
xlWhole, xlByRows, xlPrevious).Row
End With
End Function
Provded your datarange in the time sheet is continuous you can replace
rDest.Resize(151,9).Value = wbSource.Sheets(1).Range("A1:I151").Value
with
var for storing
dim TSsize as long
TSsize = wbSource.Sheets(1).Range("A1").end(xlDown).Row
rDest.Resize(TSsize,9).Value = wbSource.Sheets(1).Range("A1:I" & TSsize).Value
This is prevent the empty rows from getting into your sheet in the first place.
If the each time sheet is not a continuous range you can interate through the rows looking for empty rows and deleting them. Let me know if that is the case and i will update my answer.

Resources