I´m trying to set a array with data from a MS Excel range.
My VBA Macro replaces the text from an array with text from another array.
It works fine with arrays, but now I´m trying to fill these arrays with data from a Excel file. I´m using range and I´ve tried thousands of ways of making itwork, unsuccessfuly. I´m not a VBA coder, so maybe I´m missing some basic concepts.... :|
Heres the code. Thanks in advance for any help!
Sub ReplacePT2ES()
Dim oSld As Slide
Dim oShp As Shape
Dim oTxtRng As TextRange
Dim oTmpRng As TextRange
Dim strWhatReplace As String, strReplaceText As String
Dim x As Long
Dim xlApp As Excel.Application
Dim xlBook As Excel.Workbook
Dim rng As range
Set xlApp = CreateObject("Excel.Application")
Set xlBook = xlApp.Workbooks.Open("D:\DOCS\DiccionarioPT2ES.xlsx")
xlBook.Application.Visible = False
xlBook.Application.WindowState = xlMinimized
Dim findList As Variant
Dim replaceList As Variant
Set findList = range("A1:A3").Value
Set replaceList = range("B1:B3").Value
'-- works fine with array
'findList = Array("falha", "lei", "projeto", "falhas", "leis", "projetos", "falham", "os", "as", "gestor")
'replaceList = Array("falla", "ley", "proyecto", "fallas", "leyes", "proyectos", "fallan", "los", "las", "gerente")
'MsgBox "Iniciando!"
For x = findList.Count To replaceList.Count
' go during each slides
For Each oSld In ActivePresentation.Slides
' go during each shapes and textRanges
For Each oShp In oSld.Shapes
' replace in TextFrame
'If oShp.HasTextFrame And UBound(findList) And UBound(replaceList) > 0 Then
If oShp.HasTextFrame Then
Set oTxtRng = oShp.TextFrame.TextRange
Set oTmpRng = oTxtRng.Replace(FindWhat:=findList(x), Replacewhat:=replaceList(x), WholeWords:=True)
Do While Not oTmpRng Is Nothing
Set oTxtRng = oTxtRng.Characters(oTmpRng.Start + oTmpRng.Length, oTxtRng.Length)
Set oTmpRng = oTxtRng.Replace(FindWhat:=findList(x), Replacewhat:=replaceList(x), WholeWords:=True)
Loop
End If
Next oShp
Next oSld
Next x
xlBook.Close SaveChanges:=False
Set xlApp = Nothing
Set xlBook = Nothing
'MsgBox "Listo!"
End Sub
Finaly I found a solution: stop using Array and swith to Dictionary.
Here the code wich worked:
Set findList = range("A1:A10")
Dim MyDictionary As Object
Set MyDictionary = CreateObject("Scripting.Dictionary")
With MyDictionary
For Each RefElem In findList
If Not .Exists(RefElem) And Not IsEmpty(RefElem) Then
.Add RefElem.Value, RefElem.Offset(0, 1).Value
End If
Next RefElem
End With
Moral of the history: use the right datatype for the job ;)
You can speed up your code significantly by:
Looping through a variant array rather than a range
Splitting your IF test into two parts (VBA doesn't shortcircuit so will evaluate both parts of an AND even if the first part is False).
code
Sub Recut()
Dim X
Dim MyDictionary As Object
Dim lngRow As Long
Set MyDictionary = CreateObject("Scripting.Dictionary")
X = Range("A1:B10").Value2
With MyDictionary
For lngRow = 1 To UBound(X)
If Len(X(lngRow, 1)) > 0 Then
If Not .Exists(X(lngRow, 1)) Then .Add X(lngRow, 1), X(lngRow, 2)
End If
Next
End With
End Sub
Related
This is code the internet and I came up with. Please could you tell me what I’m doing wrong? I keep getting an error that says “can’t use a loop without a do”
Sub additions ()
Range(“BI1”) = “Comments”
Range(“V2”).Select
Do until IsEmpty(ActiveCell)
If (Range(ActiveCell) = “DM”) Then
ActiveCell.Offset(0,39).Select
Range(ActiveCell) = “Developed Markets”
ActiveCell.Offset(1,-39).Select
End If
Loop
End Sub
Add String to One Column If Another String in Another Column
Option Explicit
Sub Additions()
Dim ws As Worksheet: Set ws = ActiveSheet ' improve!
Dim srg As Range
Set srg = ws.Range("V2", ws.Cells(ws.Rows.Count, "V").End(xlUp))
Dim drg As Range: Set drg = srg.EntireRow.Columns("BI")
ws.Range("BI1").Value = "Comments"
Dim sCell As Range
Dim r As Long
For Each sCell In srg.Cells
r = r + 1
If CStr(sCell.Value) = "DM" Then ' is a match
drg.Cells(r).Value = "Developed Markets"
'Else ' is not a match; do nothing
End If
Next sCell
MsgBox "Additions finished.", vbInformation
End Sub
I want to use an array of strings that will replace the Worksheet object inside my loop, but I cant seem to figure it out.
If I declare SheetX as Variant, then I get the Object Required Error
If I declare SheetX as Object, then I get Compile Error: For Each variable on arrays must be variant
Sub DeleteAllData()
'SheetsArray = ["BalanceSheetTransposed", "IncomeStatementTransposed", "CashflowStatement"]
Dim SheetsArray(0 To 2) As Variant
Dim SheetX As Object
SheetsArray(0) = "BalanceSheetTransposed"
SheetsArray(1) = "IncomeStatementTransposed"
SheetsArray(2) = "CashflowStatement"
For Each SheetX In SheetsArray
lastrow = SheetX.Cells(Rows.Count, 1).End(xlUp).Row
lastcolumn = SheetX.Cells(1, Columns.Count).End(xlToLeft).Column
SheetX.Range("A2", Cells(lastrow, lastcolumn)).ClearContents
Next SheetX
End Sub
Out of my head 'cause I don't have Excel in this machine. Loop through the strings and set worksheet object.
Sub DeleteAllData()
Dim SheetsArray(0 To 2) As String
Dim SheetX As Worksheet
Dim name as String
SheetsArray(0) = "BalanceSheetTransposed"
SheetsArray(1) = "IncomeStatementTransposed"
SheetsArray(2) = "CashflowStatement"
For Each name In SheetsArray
set SheetX = ActiveWorkbook.worksheets(name)
lastrow = SheetX.Cells(Rows.Count, 1).End(xlUp).Row
lastcolumn = SheetX.Cells(1, Columns.Count).End(xlToLeft).Column
SheetX.Range("A2", Cells(lastrow, lastcolumn)).ClearContents
Next
End Sub
Your major problem was that you were trying to treat the strings stored in the array as if they were worksheets, but they are just strings.
The simplest way to get around it is to use Worksheets(SheetsArray) to return the worksheets that have the names you want to use, and then loop through those worksheets:
Sub DeleteAllData()
Dim SheetX As Worksheet
Dim lastRow As Long
Dim lastColumn As Long
Dim SheetsArray(0 To 2) As Variant
SheetsArray(0) = "BalanceSheetTransposed"
SheetsArray(1) = "IncomeStatementTransposed"
SheetsArray(2) = "CashflowStatement"
'An alternative to the previous 4 lines would be
'Dim SheetsArray As Variant
'SheetsArray = Array("BalanceSheetTransposed", _
' "IncomeStatementTransposed", _
' "CashflowStatement")
'Loop through the worksheets referred to in the array
For Each SheetX In Worksheets(SheetsArray)
With SheetX ' avoids some typing
lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
lastColumn = .Cells(1, .Columns.Count).End(xlToLeft).Column
'Existing code would have had issue with the unqualified Cells
'reference in the following line. You should always qualify Cells
'to specify which sheet you mean, because it defaults to
'ActiveSheet.Cells
.Range("A2", .Cells(lastRow, lastColumn)).ClearContents
End With
Next SheetX
End Sub
The Array has to be passed to the Sheets object :
Sub DeleteAllData()
Dim ws As Worksheet
For Each ws In Sheets(Array("BalanceSheetTransposed", "IncomeStatementTransposed", _
"CashflowStatement"))
s.UsedRange.Offset(1).ClearContents
Next
End Sub
My code begins with assigning the sheet and grabbing the row count
Set ws2 = ThisWorkbook.Worksheets("Sheet2")
lastRow22 As Long
lastRow22 = ws2.Cells(ws2.Rows.Count, "A").End(xlUp).Row
I have the following which put the entire column into an array from column 1 to 80
Dim arrEntireWs2() as Variant
With ws2
arrEntireWs2 = .Range(.Cells(2,1),.Cells(lastRow22,80)).Value
End With
Then I loop through it
Dim lngArrEntireWs2Index as Long
For lngArrEntireWs2Index = LBound(arrEntireWs2,1) to Ubound(arrEntireWs2,1)
'Things I want to do
Next lngArrEntireWs2Index
My question is how do I grab the value at a certain column on the row that it is looping through? Like how would I grab what is on column 10 while going through the loop?
This is what youre looking for....
Dim lngArrEntireWs2Index as Long
For lngArrEntireWs2Index = LBound(arrEntireWs2,1) to Ubound(arrEntireWs2,1)
If arrEntireWs2(lngArrEntireWs2Index, 10) Then
debug.print; arrEntireWs2(lngArrEntireWs2Index, 10)
End if
Next lngArrEntireWs2Index
this looks better to me
Dim ws2 as workbook
Set ws2 = ThisWorkbook.Worksheets("Sheet2")
Dim arr2 as Variant
With ws2
arr2 = .UsedRange
End With
Dim i as Long
For i= LBound(arr2,1) to Ubound(arr2,1)
If arr2(i, 11) Then
debug.print; arr2(i, 11)
End if
Next i
I have an Excel sheet having 3000 columns and I need to convert this sheet in such a way that one tab will contain 254 columns only and remaining will go to the next tab. So I need a VBA code (Macro) which can perform the same.
As of now I wrote the following code only which is creating 3000 tabs with one column in each, also it is going to infinite loop as I did not put any condition there for blank column.
Sub SpliteIntoMultipleTab()
'
' createtemplates Macro
Dim WS As Worksheet
Dim SS As Worksheet
Dim TemplateName As String
Dim tempstr As String
'
Dim CurCol As String
Dim Template As String
Dim xColIndex As Integer
Dim xRowIndex As Integer
Dim WSCount As Integer
'==========================================================================
'Declarations
CurCol = 1
Template = "Sheet1"
'==========================================================================
Set SS = Worksheets(Template)
If WS Is Nothing Then
Start:
With ActiveWorkbook
Set WS = .Sheets.Add(After:=ActiveSheet)
WSCount = Sheets.Add(After:=Sheets(Worksheets.Count))
On Error Resume Next
Set WS = Worksheets("temp")
WS.Name = SS.Range("A1").Value
End With
Else
End If
SS.Activate
xIndex = Application.ActiveCell.Column
xRowIndex = Application.ActiveSheet.Cells(Rows.Count, xIndex).End(xlUp).Row
Range(Cells(1, xIndex), Cells(xRowIndex, xIndex)).Select
Selection.Copy
WS.Select
WS.Range("A1").Select
ActiveSheet.Paste
SS.Columns(1).EntireColumn.Delete
CurCol = CurCol + 1
GoTo Start
End Sub
Use integer division and modulus, so for example taking the 1000th column
1000 \ 254 = 3
1000 mod 254 = 238
gives the 3rd sheet and the 238th column.
So loop through from 1 to 3000 using \ and mod.
You code is very non-standard and I cannot get my head around it, I suggest you start from my code, this is an illustrative example of breaking a block of data into separate sheets. Copy the code into a new workbook then
Run CreateSheetAndPopulateWithBlockOfData once only to create a block of data.
Run Test to run the BreakBlockIntoChunks routine, you can experiment with the chunk size.
Option Explicit
Private Const csSHEETNAME As String = "Source"
Sub TestCreateSheetAndPopualteWithBlockOfData()
Dim wsSource As Excel.Worksheet
Set wsSource = CreateSheetAndPopulateWithBlockOfData(ThisWorkbook, csSHEETNAME, 20, 100)
End Sub
Sub Test()
Dim wsSource As Excel.Worksheet
Set wsSource = ThisWorkbook.Worksheets.Item(csSHEETNAME)
'Stop
Dim wbResults As Excel.Workbook
Set wbResults = Workbooks.Add
BreakBlockIntoChunks wsSource, 5, wbResults
End Sub
Function BreakBlockIntoChunks(ByVal wsSource As Excel.Worksheet, ByVal lColumnChunkSize As Long, ByVal wbDestinationWorkbook As Excel.Workbook)
Dim rngDataBlock As Excel.Range
Set rngDataBlock = wsSource.Cells(1, 1).CurrentRegion
Dim lSourceColumnCount As Long
lSourceColumnCount = rngDataBlock.Columns.Count
Dim lSourceRowCount As Long
lSourceRowCount = rngDataBlock.Rows.Count
Dim lColumnLoop As Long
For lColumnLoop = 1 To lSourceColumnCount
Dim lCurrentSheet As Long
lCurrentSheet = ((lColumnLoop - 1) \ lColumnChunkSize) + 1
Dim wsCurrentSheet As Excel.Worksheet
If lCurrentSheet > wbDestinationWorkbook.Worksheets.Count Then Set wsCurrentSheet = wbDestinationWorkbook.Worksheets.Add
If wsCurrentSheet Is Nothing Then Set wsCurrentSheet = wbDestinationWorkbook.Worksheets.Item(lCurrentSheet) '* runs first loop
'**ADD your sheet naming logic here perhaps
Dim lCurrentColumn As Long
lCurrentColumn = ((lColumnLoop - 1) Mod lColumnChunkSize) + 1
Dim rngSource As Excel.Range
Set rngSource = wsSource.Range(wsSource.Cells(1, lColumnLoop), wsSource.Cells(lSourceRowCount, lColumnLoop))
Dim rngDestination As Excel.Range
Set rngDestination = wsCurrentSheet.Range(wsCurrentSheet.Cells(1, lCurrentColumn), wsCurrentSheet.Cells(lSourceRowCount, lCurrentColumn))
rngDestination.Value2 = rngSource.Value2 '* <---Copies without using clipboard
Next lColumnLoop
End Function
Function CreateSheetAndPopulateWithBlockOfData(ByVal wb As Excel.Workbook, ByVal sSheetName As String, ByVal lRowsDeep As Long, ByVal lColumnsWide As Long) As Excel.Worksheet
Dim ws As Excel.Worksheet
Set ws = wb.Worksheets.Add
ws.Name = sSheetName
Dim rngBlock As Excel.Range
Set rngBlock = ws.Range(ws.Cells(1, 1), ws.Cells(lRowsDeep, lColumnsWide))
rngBlock.Formula = "=RANDBETWEEN(1,100000)"
rngBlock.Value2 = rngBlock.Value2
Set CreateSheetAndPopulateWithBlockOfData = ws
End Function
you could try this:
Sub SpliteIntoMultipleTab()
Dim colNum As Long, iCol As Long
With Worksheets("Sheet1").UsedRange
colNum = .Columns.count
Do
Worksheets.Add(After:=Worksheets(Worksheets.count)).Range("A1:IT1").Resize(.Rows.count).Value = .Columns(iCol + 1).Resize(, 254).Value
iCol = iCol + 254
colNum = colNum - 254
Loop While colNum > 0
End With
End Sub
which copies values only and speed up things considerably
I've got this Excel Workbook which I want to search for a specific string in Sheet1. If it finds it, enter a new value. But, the sheet is pretty huge, so I don't think it would be very efficient to loop through each cell. So, can I search through a range and find it that way?
This is what I've got so far:
Dim rngSearchRange as range
With ThisWorkbook.Sheets(1)
Set rngSearchRange = .Range("A2:A" & .Range("A" & Rows.Count).End(xlUp).Row)
End With
The string I'm looking for is the first value in an array of three values. So, how can I search this range for that specific string, find the position and then enter a new value?
I was thinking something along this:
Dim rngFindRange as range
Set rngFindRange = rngSearchRange.Find(var(0), LookIn:=xlValues, lookat:=xlWhole)
The var(0) is the value in the array I'm after. But this line doesn't really give me any results. Am I way off here?
something like this
Sub FindMe()
Dim ws As Worksheet
Dim rngSearchRange As Range
Dim rngFindRange As Range
Dim Var
Dim elemVar
Var = Array("apples", "oranges", "fruit")
Set ws = ThisWorkbook.Sheets(1)
Set rngSearchRange = ws.Range(ws.[a2], ws.Cells(Rows.Count, "A").End(xlUp))
For Each elemVar In Var
Set rngFindRange = rngSearchRange.Find(elemVar, LookIn:=xlValues, lookat:=xlWhole)
If Not rngFindRange Is Nothing Then
MsgBox elemVar & " found in " & rngFindRange.Address(0, 0)
Else
MsgBox elemVar & " not found in:"
End If
Next elemVar
End Sub