I'm putting data from the clipboard into my array and splitting it by new lines. But I also need a second dimension splitted by tabs, but don't know how? The data in clipboard is supposed to have a fixed size, so the number of parts will be the same for each line.
What I have so far
Private Sub btnPaste_Click()
Dim Clipboard As MSForms.DataObject
Dim arrClip As Variant
Dim i As Long
Dim str As String
Dim msg As String
On Error GoTo ERRORHAND
Set Clipboard = New MSForms.DataObject
Clipboard.GetFromClipboard
str = Clipboard.GetText(1)
arrClip = Split(str, vbLf)
For i = LBound(arrClip) To UBound(arrClip)
msg = msg & arrClip(i) & vbLf
Next
MsgBox (msg)
Exit Sub
ERRORHAND:
If Err <> 0 Then Debug.Print Err.Description
End Sub
This gives me an array with new elements on each new line from clipboard, but I don't know how to add elements to a second dimension on each 'tab' found in clipboard?
Example of data in clipboard and how I want it to fill the array
Data in clipboard
Data00 Data10 Data20 Data30
Data01 Data11 Data21 Data31
Data02 Data12 Data22 Data32
Data03 Data13 Data23 Data33
etc...
Should be corresponding array element
Array(0,0) Array(1,0) Array(2,0) Array(3,0)
Array(0,1) Array(1,1) Array(2,1) Array(3,1)
Array(0,2) Array(1,2) Array(2,2) Array(3,2)
Array(0,3) Array(1,3) Array(2,3) Array(3,3)
etc...
This is your code with some adds (hope it helps)
Sub btnPaste_Click()
Dim Clipboard As MSForms.DataObject
Dim arrClip As Variant
Dim i As Long
Dim str As String
Dim msg As String
Dim arrClip2 As Variant
Dim arrClipBid() As Variant
Dim ii As Integer
'On Error GoTo ERRORHAND
Set Clipboard = New MSForms.DataObject
Clipboard.GetFromClipboard
str = Clipboard.GetText(1)
arrClip = Split(str, vbLf)
ReDim arrClipBid(LBound(arrClip) To UBound(arrClip), 0 To 0)
For i = LBound(arrClip) To UBound(arrClip)
arrClip2 = Split(arrClip(i), Chr(9))
If MaxLen < UBound(arrClip2) Then
MaxLen = UBound(arrClip2)
ReDim Preserve arrClipBid(LBound(arrClip) To UBound(arrClip), 0 To MaxLen)
End If
For ii = LBound(arrClip2) To UBound(arrClip2)
arrClipBid(i, ii) = arrClip2(ii)
msg = msg & "(" & i & ", " & ii & ")" & arrClip2(ii)
Next ii
msg = msg & vbLf
Next
MsgBox (msg)
Exit Sub
ERRORHAND:
If Err <> 0 Then Debug.Print Err.Description
End Sub
Related
I have a string of predefined worksheets, that I need to run specific code for. I get a compile error.
The code is set up to copy data from one sheet to another.
How do I do the same for multiple sheets?
When I step through the code sht is showing the MHP60,MHP61,MHP62 and not just MHP60.
I get a subscript out of range error.
Sub Prepare_CYTD_Report()
Dim addresses() As String
Dim addresses2() As String
Dim SheetNames() As String
Dim SheetNames2() As String
Dim wb1 As Workbook, wb2 As Workbook
Dim my_Filename
'Declare variables for MHP60, MHP61, MHP62 Trial Balance Values
Dim i, lastcol As Long
Dim tabNames, cell As Range
Dim tabName As String
Dim sht As Variant
addresses = Strings.Split("A9,A12:A26,A32:A38,A42:A58,A62:A70,A73:A76,A83:A90", ",") 'Trial Balance string values
addresses2 = Strings.Split("G9,G12:G26,G32:G38,G42:G58,G62:G70,G73:G76,G83:G90", ",") 'Prior Month string values
SheetNames = Strings.Split("MHP60,MHP61,MHP62")
'SheetNames2 = Strings.Split("MHP60-CYTDprior,MHP61-CYTDprior,MHP62-CYTDprior")
Set wb1 = ActiveWorkbook 'Revenue & Expenditure Summary Workbook
'*****************************Open CYTD files
my_Filename = Application.GetOpenFilename(fileFilter:="Excel Files,*.xl*;*.xm*", Title:="Select File to create CYTD Reports")
If my_Filename = False Then
Exit Sub
End If
Application.ScreenUpdating = False
Set wb2 = Workbooks.Open(my_Filename)
'*****************************Load Column Header Strings & Copy Data
For Each sht In SheetNames
lastcol = wb1.Sheets(sht).Cells(5, Columns.Count).End(xlToLeft).Column
On Error Resume Next
Set tabNames = wb1.Sheets(sht).Cells(4, 3).Resize(1, lastcol - 2).SpecialCells(xlCellTypeConstants)
'actual non-formula text values on row 4 from column C up to column lastCol'
On Error GoTo 0
If Err.Number <> 0 Then
MsgBox "No headers were found on row 4 of MHP60", vbCritical
Exit Sub
End If
For Each cell In tabNames
tabName = Strings.Trim(cell.Value2)
'dedicated variable in case of requirement for further parsing (space/comma elimination?)'
If CStr(wb1.Sheets(sht).Evaluate("ISREF('[" & wb2.Name & "]" & tabName & "'!$A$1)")) = "True" Then
'If wb2 has a tab named for the value in tabName
For i = 0 To UBound(addresses)
wb2.Sheets(tabName).Range(addresses(i)).Value2 = wb1.Sheets(sht).Range(addresses(i)).Offset(0, cell.Column - 1).Value2
'Debug.Print "data for " & wb2.Sheets(tabName).Range(addresses(i)).Address(, , , True) & " copied from " & wb1.Sheets("MHP60").Range(addresses(i)).Offset(0, cell.Column - 1).Address(, , , True)
Next i
Else
Debug.Print "A tab " & tabName & " was not found in " & wb2.Name
End If
Next cell
Next sht
MsgBox "CYTD Report Creation Complete", vbOKOnly
Application.ScreenUpdating = True
End Sub
Split by what?
SheetNames = Strings.Split("MHP60,MHP61,MHP62")
Split by comma? Then use the following instead:
SheetNames = Strings.Split("MHP60,MHP61,MHP62", ",")
Alternative
Dim SheetNames() As Variant ' needs to be Variant to work with Array()
SheetNames = Array("MHP60", "MHP61", "MHP62")
This should be quicker as your macro does not need to split the string and has it as array directly.
I want to open a txt-File, read the textlines into arrays, delete specific arrays and write all those textlines into another textfile.
It might be easier to understand if you read the code:
Sub:
Open "G:\Arbeit\gen molding\Molding.spf" For Input As #1 'code from textfile below
Dim i As Integer
Dim tlmold() As String
Do Until EOF(1) 'read into array
ReDim Preserve tlmold(i)
Line Input #1, tlmold(i)
i = i + 1
Loop
Close #1
DeleteFromArray tlmold, "M17" 'function code below
DeleteFromArray tlmold, "I_R828"
*DeleteFromArray tlmold, "I_R872"*
Dim tllength As Integer
tllength = UBound(tlmold)
For i = tllength To 0 Step -1 'newtext is the text for the new txt-file
newtext = newtext & tlmold(i) & vbCrLf
Next i
newtext = Replace(newtext, "ÿþ", "") 'remove BOM
Set Fileout = fso.CreateTextFile("G:\Arbeit\gen molding\Molding2.spf", True, True) 'create new textfile
Fileout.Write newtext
Fileout.Close
Function:
Function DeleteFromArray(ByRef Arr As Variant, StringToBeDeleted As String)
Dim arrlength As Integer
Dim strtest As String
arrlength = UBound(Arr)
strtest = StringToBeDeleted
For i = 0 To arrlength
strtest = Arr(i)
If InStr(strtest, StringToBeDeleted) <> 0 Then
Arr(i) = ""
ReDim Preserve Arr(arrlength - 1)
Exit Function
End If
Next i
End Function
Textfile "MOLDING.SPF":
G01 Z=0.1
G01 X=24.371 Z=-0.886
G03 X=24.370 Z=-1.040 CR=15.075
G01 X=24.126 Z=-12.934
G02 X=24.121 Z=-13.232 CR=50.500
G01 X=I_R830 *Z=-I_R872* ;MOLDING END PT
G01 *Z=-I_R872*-1.200
G01 X=I_R828
M17
The problem is while deleting I_R872 from the textfile, my function does notReDim the array a second time.
Because I_R872 is two times in the textfile.
So the array tlmold(5), which shouldn't exist, is just empty.
I hope you understand my "code" and can help me with my problem.
Thanks in Advance
The easiest way to accomplish what you are trying to do is simply not to place the unwanted text into the array in the first place:
Open "G:\Arbeit\gen molding\Molding.spf" For Input As #1 'code from textfile below
Dim i As Long
Dim j As Long
Dim tlmold() As String
Dim lineIn as String
Dim wanted As Boolean
Dim unwantedText
unwantedText = Array("M17","I_R828","I_R872")
Do Until EOF(1) 'read into array
'Read an input line
Line Input #1, lineIn
'Now decide whether we want that record
wanted = True
For j = LBound(unwantedText) To UBound(unwantedText)
If InStr(lineIn, unwantedText(j)) > 0 Then
wanted = False
Exit For
End If
Next
'If we want this record, re-dimension the array and store the value
If wanted Then
ReDim Preserve tlmold(i)
tlmold(i) = lineIn
i = i + 1
End If
Loop
Close #1
Dim tllength As Integer
'...
An alternative way to bypass arrays and loops is to work with the entire text of the file
Option Explicit
Public Sub UpdateFile()
Const FPATH = "G:\Arbeit\gen molding\"
Const SRC_FILE = FPATH & "Molding.spf"
Const DST_FILE = FPATH & "Molding2.spf"
Dim fullFile As String
Open SRC_FILE For Binary As #1
fullFile = Space$(LOF(1)) 'Read entire file into variable fullFile
Get #1, , fullFile
Close #1
fullFile = Replace(fullFile, "M17", vbNullString)
fullFile = Replace(fullFile, "I_R828", vbNullString)
fullFile = Replace(fullFile, "ÿþ", vbNullString)
Open DST_FILE For Output As #1
Print #1, fullFile 'Write contents back to the new file
Close #1
End Sub
Using newtext = Join(tlmold,vbCrLf) is much faster than the loop below:
For i = tllength To 0 Step -1 'newtext is the text for the new txt-file
newtext = newtext & tlmold(i) & vbCrLf
Next i
You could also use the Scripting.FileSystemObject to read the file. I refactored your code using a StringBuilder instead of an array. StringBuilders are optimized for concatenating strings.
Sub CreateNewSPF()
Const SPF_FILENAME1 = "G:\Arbeit\gen molding\Molding.spf"
Const SPF_FILENAME2 = "G:\Arbeit\gen molding\Molding2.spf"
Const ForReading = 1
Const ForWriting = 2
Dim lineIn As String
Dim fso As Object, StringBuilder As Object, TextStream1 As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Set StringBuilder = CreateObject("System.Text.StringBuilder")
Set TextStream1 = fso.OpenTextFile(SPF_FILENAME1, ForReading)
Do Until TextStream1.AtEndOfStream
lineIn = TextStream1.ReadLine
If isValidSPF(lineIn) Then StringBuilder.Append_3 lineIn & vbCrLf
Loop
TextStream1.Close
StringBuilder.Replace "ÿþ", ""
Set Fileout = fso.CreateTextFile(SPF_FILENAME2, True, True) 'create new textfile
Fileout.Write StringBuilder.ToString
Fileout.Close
End Sub
Function isValidSPF(lineIn As String) As Boolean
Dim v As Variant
For Each v In Array("M17", "I_R828", "I_R872")
If InStr(1, lineIn, v, vbTextCompare) > 0 Then Exit Function
Next
isValidSPF = True
End Function
I have this code that gets all file types.
Dim file as variant
file = Application.GetOpenFilename("All Files, *.*", , "Select File", , True)
Then I have to print it in the cells on a sheet.
For i = 1 To UBound(file)
lRow = Cells(Rows.count, 15).End(xlUp).Row
lRow = lRow + 1
ThisWorkbook.Sheets("Main").Range("O" & lRow).Value = CStr(file(i))
Next i
but what I want is first check the contents of the array. If the array has this file type, then I have to remove it in the arraylist. After that, a message will pop out that this files are removed.
dim arr() as string
arr = Split("ade|adp|app|asp|bas|bat|cer|chm|cmd|com|cpl|crt|csh|der|exe|fxp|gadget|hlp|hta|inf|ins|isp|its|js|jse|" _
& "ksh|lnk|mad|maf|mag|mam|maq|mar|mas|mat|mau|mav|maw|mda|mdb|mde|mdt|mdw|mdz|msc|msh|msh1|msh2|" _
& "mshxml|msh1xml|msh2xml|ade|adp|app|asp|bas|bat|cer|chm|cmd|com|cpl|crt|csh|der|exe|fxp|gadget|hlp|" _
& "hta|msi|msp|mst|ops|pcd|pif|plg|prf|prg|pst|reg|scf|scr|sct|shb|shs|ps1|ps1xml|ps2|ps2xml|psc1|psc2|tmp|url|vb|vbe|vbs|vsmacros|vsw|ws|wsc|wsf|wsh|xnk", "|")
I just don't know where I have to start. I have found a little bit same problem here in this post, but I just can't understand it. Thanks!
You can use a RegExp and a varaint array to do this quickly
This code looks for path... dot extension end string so it is more robust than your current array which may remove files based on the path name rather than file type
Sub B()
Dim fName As Variant
Dim objRegex As Object
Dim lngCnt As Long
Dim rng1 As Range
Set objRegex = CreateObject("vbscript.regexp")
On Error Resume Next
fName = Application.GetOpenFilename("All Files, *.*", , "Select file", , True)
If Err.Number <> 0 Then Exit Sub
On Error GoTo 0
With objRegex
.Pattern = ".*\.(ade|adp|app|asp|bas|bat|cer|chm|cmd|com|cpl|crt|csh|der|exe|fxp|gadget|hlp|hta|inf|ins|isp|its|js|jse|" _
& "ksh|lnk|mad|maf|mag|mam|maq|mar|mas|mat|mau|mav|maw|mda|mdb|mde|mdt|mdw|mdz|msc|msh|msh1|msh2|" _
& "mshxml|msh1xml|msh2xml|ade|adp|app|asp|bas|bat|cer|chm|cmd|com|cpl|crt|csh|der|exe|fxp|gadget|hlp|" _
& "hta|msi|msp|mst|ops|pcd|pif|plg|prf|prg|pst|reg|scf|scr|sct|shb|shs|ps1|ps1xml|ps2|ps2xml|psc1|psc2|tmp|url|vb|vbe|vbs|vsmacros|vsw|ws|wsc|wsf|wsh|xnk)$"
`replace matching file types with blank array entries
For lngCnt = 1 To UBound(fName)
fName(lngCnt) = .Replace(fName(lngCnt), vbNullString)
Next
End With
Set rng1 = Cells(Rows.Count, 15).End(xlUp).Offset(1,0)
'dump array to sheet
rng1.Resize(UBound(fName), 1) = Application.Transpose(fName)
` remove blank entries
On Error Resume Next
rng1.SpecialCells(xlCellTypeBlanks).Delete xlUp
On Error GoTo 0
End Sub
One way would be to check that the extension it's not present in the blacklist with InStr:
Const exts = _
".ade.adp.app.asp.bas.bat.cer.chm.cmd.com.cpl.crt.csh.der.exe.fxp.gadget" & _
".hlp.hta.inf.ins.isp.its.js.jse.ksh.lnk.mad.maf.mag.mam.maq.mar.mas.mat" & _
".mau.mav.maw.mda.mdb.mde.mdt.mdw.mdz.msc.msh.msh1.msh2.mshxml.msh1xml" & _
".msh2xml.ade.adp.app.asp.bas.bat.cer.chm.cmd.com.cpl.crt.csh.der.exe.fxp" & _
".gadget.hlp.hta.msi.msp.mst.ops.pcd.pif.plg.prf.prg.pst.reg.scf.scr.sct" & _
".shb.shs.ps1.ps1xml.ps2.ps2xml.psc1.psc2.tmp.url.vb.vbe.vbs.vsmacros.vsw" & _
".ws.wsc.wsf.wsh.xnk."
Dim file As Variant
file = Application.GetOpenFilename("All Files, *.*", , "Select File", , True)
Dim i As Long, data(), count As Long, ext As String
ReDim data(1 To UBound(file) + 1, 1 To 1)
' filter the list
For i = LBound(file) To UBound(file)
ext = LCase(Mid(file(i), InStrRev(file(i), ".")))
If InStr(1, exts, ext & ".") = 0 Then ' if not blacklisted
count = count + 1
data(count, 1) = file(i)
End If
Next
' copy the filtered list to the next available row in column "O"
If count Then
With ThisWorkbook.Sheets("Main").Cells(Rows.count, "O").End(xlUp)
.Offset(1).Resize(count).Value = data
End With
End If
I need to replace 108 images in word. I wrote VBA code so that for each inline image read in the document, the image will be replace by a new image. The new image is specified by a array that has filepaths in each element. The array comes from a text file.
For some reason, my code won't work if I have my variable, strPath as
strPath = dataArray(i)
or
strPath = Chr(34) & dataArray(i) & Chr(34)
What does work is if I type in
dataArray(0) = "C:\IMGS\G.2.1\NZ_DWH_v_SIMAP_AR1_biovalbox1_1100-1400m_Apr20-May26.png"
The path in the textfile is
C:\IMGS\G.2.1\NZ_DWH_v_SIMAP_AR1_biovalbox1_1100-1400m_Apr20-May26.png
I have 108 lines in the textfile, each for the image that needs to be replaced.
I have displayed the path in a message box and it looks like the above, so I am not sure why I can't get file paths from an array. Can someone help me?
'1-loop thru all figs
'2-bring up box to select figure
'3-add figure
Dim intChoice As Integer
Dim strPath As String
Dim objPic As InlineShape
Dim intCount As Integer
'import text
Dim dataArray() As String
Dim i As Integer
Dim g As Integer
strFileName = "C:\Users\cturner\Desktop\filesimgs_order.txt"
Open strFileName For Input As #1
dataArray = Split(Input$(LOF(1), #1), vbLf)
Close #1
g = 0
intCount = ActiveDocument.InlineShapes.Count
'loop through inline shapes
For i = 0 To intCount
strPath = Chr(34) & dataArray(i) & Chr(34)
MsgBox (TypeName(strPath))
g = g + 1
'check if valid filepath
'Debug.Print FileExists(strPath)
MsgBox strPath
'check if the current shape is an picture
If ActiveDocument.InlineShapes.Item(g).Type = wdInlineShapePicture Then
Set objPic = ActiveDocument.InlineShapes.Item(g)
objPic.Select
'insert the image
Selection.InlineShapes.AddPicture FileName:= strPath, _
LinkToFile:=False, SaveWithDocument:=True
End If
Next i
End Sub
Suprise Suprise, I forgot to trim the carriage return vbCr. After I got that out, code works fine and I am able to replace my buttload of images.
Part 1. I checked my string if it has carriage return. Main problem is that I didn't clean my string, and thus putting it into a function made vba throw the error message (no bueno). If you have it, UBound should = 1
For i = 0 To 2
strPath = dataArray(i)
checkcr = Split(strPath, vbCr)
firstIndex = LBound(checkcr)
lastIndex = UBound(checkcr)
MsgBox (firstIndex)
MsgBox (lastIndex)
MsgBox checkcr(lastIndex)
newstrPath = Replace(strPath, vbCr, "")
MsgBox newstrPath
Next i
Part 2. Corrected Code + bonus. Bouns: some code to check if the file exists (from here )
fix:
newstrPath = Replace(strPath, vbCr, "")
Updated Code:
Sub replacefigs()
' replacefigs Macro
' To replace old figures with new figures (updated disclosure)
'0-get full file paths from textfile
'1-loop thru all figs
'2-bring up box to select figure
'3-add figure
Dim intChoice As Integer
Dim strPath As String
Dim objPic As InlineShape
Dim intCount As Integer
'import text
Dim dataArray() As String
Dim i As Integer
Dim g As Integer
strFileName = "C:\Users\cturner\Desktop\filesimgs_order.txt"
Open strFileName For Input As #1
dataArray = Split(Input$(LOF(1), #1), vbLf)
Close #1
g = 0
intCount = ActiveDocument.InlineShapes.Count
'loop through inline shapes
For i = 0 To intCount
strPath = dataArray(i)
'Get rid of carriage returns
newstrPath = Replace(strPath, vbCr, "")
g = g + 1
'to check if file exists
'Debug.Print FileExists(newstrPath)
'check if the current shape is an picture
If ActiveDocument.InlineShapes.Item(g).Type = _
wdInlineShapePicture Then
Set objPic = ActiveDocument.InlineShapes.Item(g)
objPic.Select
'insert the image
Selection.InlineShapes.AddPicture FileName:= _
newstrPath, LinkToFile:=False, _
SaveWithDocument:=True
End If
Next i
End Sub
I'm very new to Excel VBA and I want to get text from clipboard into a 2D array, with first delimiter vbNewLine and second delimiter space. How do I create a 2D array with unknown size? Can I split an array, like below where I fail?
Sub CommandButton1_Click()
Dim DataObj As MsForms.DataObject
Set DataObj = New MsForms.DataObject
Dim strArray() As String
On Error GoTo ERRROR
'~~> Get data from the clipboard.
DataObj.GetFromClipboard
'~~> Get clipboard contents
myString = DataObj.GetText(1)
'~~> Split into string, delimiter vbNewLine
strArray = Split(myString, vbNewLine)
Here is here I fail
'~~> Split each strArray and store in strArray2, delimiter " ".
Dim strArray2() As String
For ii = LBound(strArray2) To UBound(strArray2)
strArray2(ii) = Split(strArray(ii))
Next ii
Exit Sub
ERRROR:
If Err <> 0 Then
'Handel error
End If
End Sub
You are doing it the wrong way.
Is this what you are trying? (UNTESTED)
Sub CommandButton1_Click()
Dim DataObj As MsForms.DataObject
Dim strArray, strArray2
Dim i As Long, j As Long
Dim myString As String
On Error GoTo ERRROR
Set DataObj = New MsForms.DataObject
'~~> Get data from the clipboard.
DataObj.GetFromClipboard
'~~> Get clipboard contents
myString = DataObj.GetText(1)
'~~> Split myString, delimiter vbNewLine
strArray = Split(myString, vbNewLine)
'~~> Split each strArray and store in strArray2, delimiter " ".
For i = LBound(strArray) To UBound(strArray)
strArray2 = Split(strArray(i))
For j = LBound(strArray2) To UBound(strArray2)
Debug.Print strArray2(j)
Next j
Next i
Exit Sub
ERRROR:
If Err <> 0 Then Debug.Print Err.Description
End Sub