I have a word document that contains a number of tables. I've written a script to retrieve the tables starting at a specified table number i.e. table 1, 2, 3, or 4 and so on (user selects). The script then pulls the tables into an excel workbook. The problem I am having is that all of the tables have 4 columns. The 3rd column has content in it which contains multiple lines so when it pastes to excel, it looks bad. I understand that if you copy the 3rd column of any table, double click in a cell in excel and paste, it'll paste in the line breaks so it looks ok. Was wondering if there was a way to do this in vba.
Here is my table that I want to copy into Excel:
Here is what it looks like it when the script pastes it in:
Here is what I needed it to look like:
Here's what I have so far:
Option Explicit
Sub Macro1()
Dim wdDoc As Object
Dim wdFileName As Variant
Dim tableNo As Integer 'table number in Word
Dim iRow As Long 'row index in Excel
Dim iCol As Integer 'column index in Excel
Dim resultRow As Long
Dim tableStart As Integer
Dim tableTot As Integer
On Error Resume Next
ActiveSheet.Range("A:AZ").ClearContents
wdFileName = Application.GetOpenFilename("Word files (*.docx),*.docx", , _
"Browse for file containing table(s) to be imported")
If wdFileName = False Then Exit Sub '(user cancelled import file browser)
Set wdDoc = GetObject(wdFileName) 'open Word file
With wdDoc
tableNo = wdDoc.Tables.Count
tableTot = wdDoc.Tables.Count
If tableNo = 0 Then
MsgBox "This document contains no tables", _
vbExclamation, "Import Word Table"
ElseIf tableNo > 1 Then
tableNo = InputBox("This Word document contains " & tableNo & " tables." & vbCrLf & _
"Enter the table to start from", "Import Word Table", "1")
End If
resultRow = 1
For tableStart = 1 To tableTot
With .Tables(tableStart)
'copy cell contents from Word table cells to Excel cells
For iRow = 1 To .Rows.Count
For iCol = 1 To .Columns.Count
Cells(resultRow, iCol) = WorksheetFunction.Clean(.Cell(iRow, iCol).Range.Text)
Next iCol
resultRow = resultRow + 1
Next iRow
End With
resultRow = resultRow + 1
Next tableStart
End With
End Sub
I've found this solution which still requires the cell-wise iteration (unfortunately the line breaks are treated as cell delimiters when Pasting directly to Excel using Paste, PasteSpecial or several of the CommandBars.ExecuteMso options.
Try replacing the Ascii 13 character with a vbCrLf (carriage return + line feed) and also replacing Ascii 7 with an empty string:
Dim thisText as String, newText as String
For tableStart = 1 To tableTot
With .Tables(tableStart)
'copy cell contents from Word table cells to Excel cells
For iRow = 1 To .Rows.Count
For iCol = 1 To .Columns.Count
thisText = .Cell(iRow, iCol).Range.Text
newText = Replace(thisText, Chr(13), vbCrLf)
newText = Replace(newText, Chr(7), vbNullString)
Cells(resultRow, iCol) = WorksheetFunction.Clean(newText)
Next iCol
resultRow = resultRow + 1
Next iRow
End With
resultRow = resultRow + 1
Next tableStart
There may be a more elegant way to do this without looping row/column, but for now this should work.
Actual code that I tested
Sub foo2()
Dim wdApp As Object, wdDoc As Object, wdTable As Object
Set wdApp = GetObject(, "Word.Application")
Set wdDoc = wdApp.Documents(1)
Set wdTable = wdDoc.Tables(1)
Dim iRow As Long, iCol As Long, resultRow As Long
Dim thisText As String, newText As String
resultRow = 1
With wdTable
For iRow = 1 To .Rows.Count
For iCol = 1 To .Columns.Count
thisText = .Cell(iRow, iCol).Range.Text
newText = Replace(thisText, Chr(13), vbCrLf)
newText = Replace(newText, Chr(7), vbNullString)
Cells(resultRow, iCol) = newText
Next iCol
resultRow = resultRow + 1
Next iRow
End With
End Sub
Related
I have VBA code that returns external file details like path, type, last modified date, last created date etc. for files in a folder.
I want to return the details for files in the sub-folders of that folder.
Dim IRow
Sub ListFiles()
IRow = 11 'where you want your first row of data
Call ListMyFiles(Range("B5"), False) 'Where B5 is your filepath (eg, C:\)
End Sub
Sub ListMyFiles(MySourcePath, includesubfolders)
Dim xSubFolder As Object
Set MyObject = New FileSystemObject
Set mysource = MyObject.GetFolder(MySourcePath)
On Error Resume Next
For Each myfile In mysource.Files
icol = 1
Cells(IRow, icol).Value = myfile.Path
icol = icol + 1
Cells(IRow, icol).Value = myfile.Name
icol = icol + 1
Cells(IRow, icol).Value = myfile.Type
icol = icol + 1
Cells(IRow, icol).Value = myfile.DateLastModified
icol = icol + 1
Cells(IRow, icol).Value = myfile.DateCreated
icol = icol + 1
IRow = IRow + 1
Next
If xIsSubfolders Then
For Each xSubFolder In xFolder.subfolders
ListFilesInFolder xSubFolder.Path, True
Next xSubFolder
End If
Set xFile = Nothing
Set xFolder = Nothing
Set xFileSystemObject = Nothing
End Sub
I haven't tested this, but basically what you want is recursion. This is when you call the subroutine/function while in that function. Basically it's the subroutine calling itself every time it finds a subfolder.
Something like:
Dim IRow
Sub ListFiles()
IRow = 11 'where you want your first row of data
Call ListMyFiles(Range("B5"), False) 'Where B5 is your filepath (eg, C:\)
End Sub
Sub ListMyFiles(MySourcePath as string, includesubfolders as boolean)
Set MyObject = New FileSystemObject
Set mysource = MyObject.GetFolder(MySourcePath)
On Error Resume Next
For Each myfile In mysource.Files
icol = 1
Cells(IRow, icol).Value = myfile.Path
icol = icol + 1
Cells(IRow, icol).Value = myfile.Name
icol = icol + 1
Cells(IRow, icol).Value = myfile.Type
icol = icol + 1
Cells(IRow, icol).Value = myfile.DateLastModified
icol = icol + 1
Cells(IRow, icol).Value = myfile.DateCreated
icol = icol + 1
IRow = IRow + 1
Next
'Check if the subroutine was called to include subfolders
If includesSubFolders Then
'Loop through all of the subfolders in the FSO folder
For Each SubFolder in mysource.SubFolders
'Call this same subroutine
ListMyFiles(Subfolder.Path, true)
Next xSubFolder
End If
End Sub
A lot of things can be simplified here. More importantly, the folder transversing needs to be a recursive call in order to go through to all subfolder levels.
Here is a sample code that does this. The first argument to ListMyFiles is the cell location where the path is stored, and the second argument when you want the file list to start.
Sub ListFiles()
Call ListMyFiles(Sheet1.Range("B5"), Sheet1.Range("B11"), True)
End Sub
Sub ListMyFiles(ByVal r_SourcePath As Range, ByRef r_List As Range, Optional includesubfolders As Boolean = False)
Dim path As String, ff As Folder
path = r_SourcePath.Text
Dim fso As New FileSystemObject
Set ff = fso.GetFolder(path)
Call ListFileInFolder(r_List, ff, includesubfolders)
End Sub
Public Sub ListFileInFolder(ByRef r_List As Range, ByRef ff As Folder, Optional inclSubFolders As Boolean = False)
On Error Resume Next
Dim index As Long, n As Long
index = 0
Dim f As File
For Each f In ff.Files
r_List.Offset(index, 0).Resize(1, 5).Value2 = _
Array(f.path, f.Name, f.Type, f.DateLastModified, f.DateCreated)
index = index + 1
Next
If inclSubFolders Then
For Each ff In ff.SubFolders
n = ff.Files.Count
If n > 0 Then
Call ListFileInFolder(r_List.Offset(index, 0), ff, True)
index = index + n
End If
Next
End If
On Error GoTo 0
End Sub
Of note here is the writing of a single row of data of 5 columns using a single line and the Array() function.
I've been looking around to find out why this is giving me a Run-time error '1004' You can't paste this here because the Copy area and paste area aren't the same size. Select just one cell in the paste area or an area that's the same size, and try pasting again. but I've had no luck with the solutions I've found.
The problem here happens only on this line: ws.Columns(1).Copy Destination:=ws2.Columns(1).Rows(5)
The paste content should be just a few cells vertically i.e. "B1:B5". I can't do Range("B1:B5") because I need to have it constantly update depending on a couple of things.
Any ideas as to why I'm getting the error?
Option Explicit
Sub chkPercent()
Dim wb As Workbook
Dim ws As Worksheet
Dim ws2 As Worksheet
Dim rng As Range
Set wb = ActiveWorkbook
Set ws = wb.Worksheets(1)
Set rng = ws.Range("A1")
Dim iq_Array As Variant
Dim colNumb As Long
Dim rowNumb As Long
Application.ScreenUpdating = False
colNumb = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
rowNumb = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
Dim iQRef() As String
Dim iCol As Long
Dim pptText As String
ReDim iQRef(colNumb)
' capture IQ refs locally
For iCol = 2 To colNumb
iQRef(iCol) = ws.Cells(1, iCol).Value
Next iCol
Worksheets.Add After:=ws
Set ws2 = wb.Worksheets(2)
pptText = "iq_1,2,3,4"
'Identify if within text there is "iq_"
'If InStr(1, pptText, "iq_") <= 0 Then GoTo nextShpe
'set iq_Array as an array of the split iq's
iq_Array = Split(pptText, ",")
Dim hasIQs As Boolean
Dim checkStr As String
Dim pCol As Long
Dim checkOne
Dim arrayLoop As Long
checkOne = iq_Array(0)
hasIQs = Left(checkOne, 3) = "iq_"
If hasIQs Then
' paste inital column into temporary worksheet
ws.Columns(1).Copy Destination:=ws2.Columns(1)
End If
' loop for each iq_ in the array
For arrayLoop = LBound(iq_Array) To UBound(iq_Array)
' Take copy of potential ref and adjust to standard if required
checkStr = iq_Array(arrayLoop)
If hasIQs And Left(checkStr, 3) <> "iq_" Then checkStr = "iq_" & checkStr
Dim iQRefArray As Variant
Dim iQRefString As String
Dim checkRefStr As String
Dim nCol As Long
Dim doUntilCheck As String
Dim rowCount As Long
Dim copy1
Dim paste1
doUntilCheck = 99
' Look for existence of corresponding column in local copy array
pCol = 0
For iCol = 2 To colNumb
iQRefString = Left(iQRef(iCol), Len(iQRef(iCol)) - 1)
iQRefArray = Replace(iQRefString, "__", "_")
iQRefArray = Split(iQRefArray, "_")
checkRefStr = "iq_" & iQRefArray(1)
If checkStr = checkRefStr Then
pCol = iCol
Exit For
End If
Next iCol
If pCol > 0 Then
' Paste the corresponding column into the forming table
ws.Columns(pCol).Copy Destination:=ws2.Columns(2)
If iQRefArray(2) = "00" Then GoTo nxtArrayLoop
nCol = 0
rowCount = 1
Do Until doUntilCheck = "00"
Do Until doUntilCheck = "01"
nCol = nCol + 1
rowCount = rowCount + rowNumb
iQRefString = Left(iQRef(iCol + nCol), Len(iQRef(iCol + nCol)) - 1)
iQRefArray = Replace(iQRefString, "__", "_")
iQRefArray = Split(iQRefArray, "_")
doUntilCheck = iQRefArray(2)
If doUntilCheck = "00" Then GoTo nxtArrayLoop
If doUntilCheck = "01" Then GoTo nxtArrayLoop
ws.Columns(1).Copy Destination:=ws2.Columns(1).Rows(rowCount)
ws.Columns(pCol + nCol).Copy Destination:=ws2.Columns(2).Rows(rowCount)
Loop
Loop
End If
nxtArrayLoop:
Next arrayLoop
Application.ScreenUpdating = True
End Sub
The error is just as it says it is. The copy and paste ranges are two different sizes.
The code tries to copy an entire column (ws.Columns(1).Copy) into a defined range (Destination:=ws2.Columns(1).Rows(5) - which I think is one cell, but I have never used that type of syntax before).
If you need to define the copy range to be dynamic than do this:
ws.Range(ws.Cells(ws.Rows.Count,1).End(Xlup),ws.Cells(1,1)).Copy Destination:=ws2.Cells(1,1)
This assumes contiguous cells starting in row 1 of column A in ws.
I need a macro to split my data from one Excel file to few others. It looks like this:
UserList.xls
User Role Location
DDAVIS XX WW
DDAVIS XS WW
GROBERT XW WP
SJOBS XX AA
SJOBS XS AA
SJOBS XW AA
I need, to copy data like this:
WW_DDAVIS.xls
User Role
DDAVIS XX
DDAVIS XS
WP_GROBERT.xls
User Role
GROBERT XW
AA_SJOBS.xls
User Role
SJOBS XX
SJOBS XS
SJOBS XW
I need every user, to have his own file. The problem appeared when I was told that the files need to be filled using template (template.xls). Looks the same, but data in the source file starts in cell A2, and in the template file from cell A8.
To copy data without template I used this code:
Public Sub SplitToFiles()
' MACRO SplitToFiles
' Last update: 2012-03-04
' Author: mtone
' Version 1.1
' Description:
' Loops through a specified column, and split each distinct values into a separate file by making a copy and deleting rows below and above
'
' Note: Values in the column should be unique or sorted.
'
' The following cells are ignored when delimiting sections:
' - blank cells, or containing spaces only
' - same value repeated
' - cells containing "total"
'
' Files are saved in a "Split" subfolder from the location of the source workbook, and named after the section name.
Dim osh As Worksheet ' Original sheet
Dim iRow As Long ' Cursors
Dim iCol As Long
Dim iFirstRow As Long ' Constant
Dim iTotalRows As Long ' Constant
Dim iStartRow As Long ' Section delimiters
Dim iStopRow As Long
Dim sSectionName As String ' Section name (and filename)
Dim rCell As Range ' current cell
Dim owb As Workbook ' Original workbook
Dim sFilePath As String ' Constant
Dim iCount As Integer ' # of documents created
iCol = Application.InputBox("Enter the column number used for splitting", "Select column", 2, , , , , 1)
iRow = Application.InputBox("Enter the starting row number (to skip header)", "Select row", 5, , , , , 1)
iFirstRow = iRow
Set osh = Application.ActiveSheet
Set owb = Application.ActiveWorkbook
iTotalRows = osh.UsedRange.Rows.Count
sFilePath = Application.ActiveWorkbook.Path
If Dir(sFilePath + "\Split", vbDirectory) = "" Then
MkDir sFilePath + "\Split"
End If
'Turn Off Screen Updating Events
Application.EnableEvents = False
Application.ScreenUpdating = False
Do
' Get cell at cursor
Set rCell = osh.Cells(iRow, iCol)
sCell = Replace(rCell.Text, " ", "")
If sCell = "" Or (rCell.Text = sSectionName And iStartRow <> 0) Or InStr(1, rCell.Text, "total", vbTextCompare) <> 0 Then
' Skip condition met
Else
' Found new section
If iStartRow = 0 Then
' StartRow delimiter not set, meaning beginning a new section
sSectionName = rCell.Text
iStartRow = iRow
Else
' StartRow delimiter set, meaning we reached the end of a section
iStopRow = iRow - 1
' Pass variables to a separate sub to create and save the new worksheet
CopySheet osh, iFirstRow, iStartRow, iStopRow, iTotalRows, sFilePath, sSectionName, owb.fileFormat
iCount = iCount + 1
' Reset section delimiters
iStartRow = 0
iStopRow = 0
' Ready to continue loop
iRow = iRow - 1
End If
End If
' Continue until last row is reached
If iRow < iTotalRows Then
iRow = iRow + 1
Else
' Finished. Save the last section
iStopRow = iRow
CopySheet osh, iFirstRow, iStartRow, iStopRow, iTotalRows, sFilePath, sSectionName, owb.fileFormat
iCount = iCount + 1
' Exit
Exit Do
End If
Loop
'Turn On Screen Updating Events
Application.ScreenUpdating = True
Application.EnableEvents = True
MsgBox Str(iCount) + " documents saved in " + sFilePath
End Sub
Public Sub DeleteRows(targetSheet As Worksheet, RowFrom As Long, RowTo As Long)
Dim rngRange As Range
Set rngRange = Range(targetSheet.Cells(RowFrom, 1), targetSheet.Cells(RowTo, 1)).EntireRow
rngRange.Select
rngRange.Delete
End Sub
Public Sub CopySheet(osh As Worksheet, iFirstRow As Long, iStartRow As Long, iStopRow As Long, iTotalRows As Long, sFilePath As String, sSectionName As String, fileFormat As XlFileFormat)
Dim ash As Worksheet ' Copied sheet
Dim awb As Workbook ' New workbook
' Copy book
osh.Copy
Set ash = Application.ActiveSheet
' Delete Rows after section
If iTotalRows > iStopRow Then
DeleteRows ash, iStopRow + 1, iTotalRows
End If
' Delete Rows before section
If iStartRow > iFirstRow Then
DeleteRows ash, iFirstRow, iStartRow - 1
End If
' Select left-topmost cell
ash.Cells(1, 1).Select
' Clean up a few characters to prevent invalid filename
sSectionName = Replace(sSectionName, "/", " ")
sSectionName = Replace(sSectionName, "\", " ")
sSectionName = Replace(sSectionName, ":", " ")
sSectionName = Replace(sSectionName, "=", " ")
sSectionName = Replace(sSectionName, "*", " ")
sSectionName = Replace(sSectionName, ".", " ")
sSectionName = Replace(sSectionName, "?", " ")
' Save in same format as original workbook
ash.SaveAs sFilePath + "\Split\" + sSectionName, fileFormat
' Close
Set awb = ash.Parent
awb.Close SaveChanges:=False
End Sub
The problem in this one, is that I have no idea how to make name not DDAVIS.xls, but using WW_DDAVIS.xls (location_user.xls). Second problem - Use template. This code just copies whole workbook and erases all wrong data. All I need, is to copy value of the right data to this template.
Unfortunately I didn't find working code and I'm not so fluent in VBA to make it alone.
I tried other one, that worked only in half. It copied the template to every file and name it properly, but I couldn't figure out how to copy cells to the right files.
Option Explicit
Sub copyTemplate()
Dim lRow, x As Integer
Dim wbName As String
Dim fso As Variant
Dim dic As Variant
Dim colA As String
Dim colB As String
Dim colSep As String
Dim copyFile As String
Dim copyTo As String
Set dic = CreateObject("Scripting.Dictionary") 'dictionary to ensure that duplicates are not created
Set fso = CreateObject("Scripting.FileSystemObject") 'file scripting object for fiile system manipulation
colSep = "_" 'separater between values of col A and col B for file name
dic.Add colSep, vbNullString ' ensuring that we never create a file when both columns are blank in between
'get last used row in col A
lRow = Range("A" & Rows.Count).End(xlUp).Row
x = 1
copyFile = "c:\location\Template.xls" 'template file to copy
copyTo = "C:\location\List\" 'location where copied files need to be copied
Do
x = x + 1
colA = Range("G" & x).Value 'col a value
colB = Range("A" & x).Value ' col b value
wbName = colA & colSep & colB ' create new file name
If (Not dic.Exists(wbName)) Then 'ensure that we have not created this file name before
fso.copyFile copyFile, copyTo & wbName & ".xls" 'copy the file
dic.Add wbName, vbNullString 'add to dictionary that we have created this file
End If
Loop Until x = lRow
Set dic = Nothing ' clean up
Set fso = Nothing ' clean up
End Sub
sub test()
dim wb
dim temp
dim rloc
rloc= "result files location"
set wb =thisworkbook
set temp= workbook.open(template path)
' getting last row
lrow=wb.sheets(1).range("A1:A"&rows.count).end(xlup).row
icounter=0
for i=2 to lrow 'leaving out the header row
with wb.sheets(1)
if cells(i,1).value=cells(i,1).offset(1,1).value then
icounter=icounter+1
else
if icounter>0 then
range(cells(i,1):(cells(i,1).offset(-icounter,2)).copy
wb.sheet(8,1).pastespecial xlvalues
application.cutcopymode=false
filename=str(cells(i,1).value) & "_" & str(cells(i,3).value) & "".xls"
chdir rloc
temp.saveas(filename,xlworkbookdefault)
else
range(cells(i,1):cells(i,2)).copy
wb.sheets(8,1).pastespecial xlvalues
application.cutcopymode=false
filename=str(cells(i,1).value) & "_" & str(cells(i,3).value) & ".xls"
chdir rloc
temp.saveas(filename,xlworkbookdefault)
end if
end if
end with
next i
wb.close savechanges:=false
temp.close savechanges:=false
end sub
this might work. i haven't tested the code. its a bit crude. i am also just a beginner in vba. forgive me if it contains errors.
look at the logic. if its all you want create a code from scratch yourself.
#Sivaprasath V
Thanks, looks like it should work. I've changed it a little bit, to look better and to fix some issues
Sub test()
Dim wb
Dim temp
Dim rloc
rloc = "C:\LOCATION\result\"
Set wb = ThisWorkbook
Set temp = Workbooks.Open("C:\LOCATION\Template.xls")
' getting last row
lRow = wb.Sheets(1).Range("A1:A" & Rows.Count).End(xlDown).Row 'changed xlUp for xlDown
icounter = 0
For i = 2 To lRow 'leaving out the header row
With wb.Sheets(1)
Range("C2").Value = Cells(i, 1).Value
If Cells(i, 1).Value = Cells(i, 1).Offset(1, 0).Value Then 'changed offset from (1,1)
icounter = icounter + 1
Else
If icounter > 0 Then
Range(cells(i,1):(cells(i,1).offset(-icounter,7)).Copy 'error
wb.Sheet(8, 1).PasteSpecial xlValues
Application.CutCopyMode = False
Filename = Str(Cells(i, 1).Value) & "_" & Str(Cells(i, 3).Value) & ".xls"
ChDir rloc
temp.SaveAs Filename, xlWorkbookDefault
Else
Range(cells(i,1):cells(i,7)).Copy 'error
wb.Sheets(8, 1).PasteSpecial xlValues
Application.CutCopyMode = False
Filename = Str(Cells(i, 1).Value) & "_" & Str(Cells(i, 3).Value) & ".xls"
ChDir rloc
temp.SaveAs Filename, xlWorkbookDefault
End If
End If
End With
Next i
wb.Close savechanges:=False
temp.Close savechanges:=False
End Sub
I'm fighting with an error that i can't quite understand. In line:
Range(cells(i,1):(cells(i,1).offset(-icounter,7)).Copy
and this:
Range(cells(i,1):cells(i,7)).Copy
There is an error saying:
Compile error:
Expected: list separator or )
Can't figure out how to fix it. Code looks good for me.
#EDIT
Went around the error using new variable ("C" & i & ":" & "F" & i - icounter)
after some minor changes it worked, thanks :)
I am trying to transfer Word tables to Excel - this has already been done here - and in addition, during the transfer I'd like to keep only rows that contain certain content, and would like to reshape the table before pasting it into Excel. I thought this could be done by converting each table first into an Excel array and then modifying the array as needed before pasting it to a specified range. Yet, I am not so familiar with Word VBA and I am finding this task pretty hard. I am starting from this code here, which I found at the post referenced above.
Option Explicit
Sub ImportWordTable()
Dim wdDoc As Object
Dim wdFileName As Variant
Dim tableNo As Integer 'table number in Word
Dim iRow As Long 'row index in Excel
Dim iCol As Integer 'column index in Excel
Dim resultRow As Long
Dim tableStart As Integer
Dim tableTot As Integer
On Error Resume Next
ActiveSheet.Range("A:AZ").ClearContents
wdFileName = Application.GetOpenFilename("Word files (*.docx),*.doc", , _
"Browse for file containing table to be imported")
If wdFileName = False Then Exit Sub '(user cancelled import file browser)
Set wdDoc = GetObject(wdFileName) 'open Word file
With wdDoc
tableTot = wdDoc.tables.Count
If tableTot = 0 Then
MsgBox "This document contains no tables", _
vbExclamation, "Import Word Table"
End If
For tableStart = 1 To tableTot
With .tables(tableStart)
'copy cell contents from Word table cells to Excel cells
For iRow = 1 To .Rows.Count
For iCol = 1 To .Columns.Count
Cells(resultRow, iCol) = WorksheetFunction.Clean(.cell(iRow, iCol).Range.Text)
Next iCol
resultRow = resultRow + 1
Next iRow
End With
resultRow = resultRow + 1
Next tableStart
End With
End Sub
I think I should change this chunk to obtain what I am looking for.
For tableStart = 1 To tableTot
With .tables(tableStart)
'copy cell contents from Word table cells to Excel cells
For iRow = 1 To .Rows.Count
For iCol = 1 To .Columns.Count
Cells(resultRow, iCol) = WorksheetFunction.Clean(.cell(iRow, iCol).Range.Text)
Next iCol
resultRow = resultRow + 1
Next iRow
End With
resultRow = resultRow + 1
Next tableStart
End With
Can someone help me with this? I can provide more details if needed. Many thanks!
Riccardo
If you want to copy only certain rows:
For tableStart = 1 To tableTot
With .tables(tableStart)
For iRow = 1 To .Rows.Count
v = WorksheetFunction.Clean(.cell(iRow, 1).Range.Text)
If v = "A" Or v = "B" Or v = "C" Then
For iCol = 1 To .Columns.Count
Cells(resultRow, iCol) = WorksheetFunction.Clean( _
.cell(iRow, iCol).Range.Text)
Next iCol
resultRow = resultRow + 1
End If
Next iRow
End With
resultRow = resultRow + 1
Next tableStart
With the help of Tim, this is the code that does what I was looking for.
Sub ImportWordTable()
Dim wdDoc As Object
Dim wdFileName, v, cont As Variant
Dim tableNo As Integer 'table number in Word
Dim iRow As Long 'row index in Excel
Dim iCol As Integer 'column index in Excel
Dim resultRow As Long
Dim tableStart As Integer
Dim tableTot As Integer
Dim rtemp, i As Integer
Dim categ(4), content(4) As Variant
Dim found, temprange As Range
Worksheets.Add.Name = "tempsht"
Worksheets.Add.Name = "final"
With Sheets("final")
.Cells(1, 1) = "Author"
.Cells(1, 2) = "Title"
.Cells(1, 3) = "Date"
.Cells(1, 4) = "Publication name"
.Cells(1, 5) = "Word count"
End With
categ(0) = "BY"
categ(1) = "HD"
categ(2) = "PD"
categ(3) = "SN"
categ(4) = "WC"
resultRow = 2
wdFileName = Application.GetOpenFilename("Word files (*.rtf),*.rtf", , "Browse for file containing table to be imported")
If wdFileName = False Then Exit Sub '(user cancelled import file browser)
Set wdDoc = GetObject(wdFileName) 'open Word file
With wdDoc
tableTot = wdDoc.tables.Count
If tableTot = 0 Then
MsgBox "This document contains no tables", _
vbExclamation, "Import Word Table"
End If
For tableStart = 1 To tableTot - 1
With .tables(tableStart) 'subset the table and copy it to a tempsheet
rtemp = 1
For iRow = 1 To .Rows.Count
v = WorksheetFunction.Clean(.cell(iRow, 1).Range.Text)
If v = " HD" Or v = " BY" Or v = " WC" Or v = " PD" Or v = " SN" Or v = "HD" Or v = "BY" Or v = "WC" Or v = "PD" Or v = "SN" Then
For iCol = 1 To .Columns.Count
Sheets("tempsht").Cells(rtemp, iCol) = Trim(WorksheetFunction.Clean(.cell(iRow, iCol).Range.Text))
Next iCol
rtemp = rtemp + 1
End If
Next iRow
Set temprange = Sheets("tempsht").Range("A1:A5")
With temprange
For i = 0 To 4
Set found = .find(What:=categ(i))
If found Is Nothing Then
content(i) = ""
Else
content(i) = Sheets("tempsht").Cells(found.Row, 2).Value
End If
Next i
End With
Sheets("final").Range(Cells(resultRow, 1), Cells(resultRow, 5)) = content
Sheets("tempsht").Range("A1:B5").ClearContents 'remove content from tempsheet
End With
resultRow = resultRow + 1
Next tableStart
Application.DisplayAlerts = False 'delete temporary sheet
Sheets("tempsht").Select
ActiveWindow.SelectedSheets.Delete
End With
End Sub
I have an Excel spreadsheet of data for work that I need to split up in VBA. A couple of columns have multiple lines of text and others do not. I've figured out how to split the multiple lines of text, my problem is taking the column with a single line of text and copying it down. For example:
Company_Name Drug_1 Phase_2 USA
Drug_2 Discontinued
Drug_3 Phase_1 Europe
Drug_4 Discontinued
Below is the code I am using to split columns B & C and then I can handle D manually, however I need column A to copy down into rows 2-4. There's over 600 rows like this otherwise I would just do it manually. (Note: I'm putting column B into A below, and column C into C)
Sub Splitter()
Dim iPtr1 As Integer
Dim iPtr2 As Integer
Dim iBreak As Integer
Dim myVar As Integer
Dim strTemp As String
Dim iRow As Integer
'column A loop
iRow = 0
For iPtr1 = 1 To Cells(Rows.Count, 1).End(xlUp).Row
strTemp = Cells(iPtr1, 1)
iBreak = InStr(strTemp, vbLf)
Range("C1").Value = iBreak
Do Until iBreak = 0
If Len(Trim(Left(strTemp, iBreak - 1))) > 0 Then
iRow = iRow + 1
Cells(iRow, 2) = Left(strTemp, iBreak - 1)
End If
strTemp = Mid(strTemp, iBreak + 1)
iBreak = InStr(strTemp, vbLf)
Loop
If Len(Trim(strTemp)) > 0 Then
iRow = iRow + 1
Cells(iRow, 2) = strTemp
End If
Next iPtr1
'column C loop
iRow = 0
For iPtr2 = 1 To Cells(Rows.Count, 3).End(xlUp).Row
strTemp = Cells(iPtr2, 3)
iBreak = InStr(strTemp, vbLf)
Do Until iBreak = 0
If Len(Trim(Left(strTemp, iBreak - 1))) > 0 Then
iRow = iRow + 1
Cells(iRow, 4) = Left(strTemp, iBreak - 1)
End If
strTemp = Mid(strTemp, iBreak + 1)
iBreak = InStr(strTemp, vbLf)
Loop
If Len(Trim(strTemp)) > 0 Then
iRow = iRow + 1
Cells(iRow, 4) = strTemp
End If
Next iPtr2
End Sub
There is a bit of code I call the "waterfall fill" which does exactly this. If you can build a range of cells to fill (i.e. set rng_in), it will do it. It works on any number of columns which is a nice feature. You can honestly feed it a range of A:D and it will polish off your blanks.
Sub FillValueDown()
Dim rng_in As Range
Set rng_in = Range("B:B")
On Error Resume Next
Dim rng_cell As Range
For Each rng_cell In rng_in.SpecialCells(xlCellTypeBlanks)
rng_cell = rng_cell.End(xlUp)
Next rng_cell
On Error GoTo 0
End Sub
Before and after, shows the code filling down.
How it works
This code works by getting a range of all the blank cells. By default SpecialCells only looks into the UsedRange because of a quirk with xlCellTypeBlanks. From there it sets the value of the blank cell equal to the closest cell on top of it using End(xlUp). The error handling is in place because xlCellTypeBlanks will return an error if nothing is found. If you do the whole column with a blank row at top though (like the picture), the error will never get triggered.