Range(Cells(... working incorrectly - vba

I have a little problem with a VBA range being used in excel:
dim frameRefPoint As String
frameRefPoint = "4,4"
range(Cells(frameRefPoint).Offset(0,0), Cells(frameRefPoint).Offset(7, 7)).Interior ...
This isn't behaving as I expect it to. I think that the first cell in the specified Range(Cells(4,4).Offset(0,0)) should be "D4", but when I use the range in a code, the first cell of the range is "D1" ~ cells(1,4).
The address property of cells(frameRefPoint) returns $D$1. What am I missing here?

You cannot span two paramters (e.g. .Cells(<row>, <column>)) by concatenating the values with an interim comma. Just making it 'look' like what you code is not the same as legitimate code. You can however, use variables for each parameter.
dim r as long, c as long, frameRefPoint As string
r = 4
c = 4
cells(r, c).resize(7, 7) = "this works"
frameRefPoint = "4,4"
'split the string on the comma and convert teh text-that-looks-numbers to actual numbers
cells(int(split(frameRefPoint, ",")(0))), int(split(frameRefPoint, ",")(1)).resize(7, 7) = "this also works"

Range(Cells(CInt(Split(frameRefPoint, ",")(0)), CInt(Split(frameRefPoint, ",")(1))).Offset(0, 0), Cells(CInt(Split(frameRefPoint, ",")(0)), CInt(Split(frameRefPoint, ",")(1))).Offset(7, 7)).Interior....

Related

How do I have my code recognize cells with a specific string STRUCTURE, while ignoring others?

So, here's what I'm facing.
I have a bit of vba code, that will find every cell in a single column containing a specific string. The words it looks for are in an array called totArray. This works well.
Problem is, when a word in the cell contains "SUBTOTAL" or something similar, it will still find it and copy it. Also, there will be words where TOTAL or TOTAAL aren't followed by numbers of unknown length.
Please see my code attached. How do I get it so that it will find every case where the cell contains TOTAL or TOTAAL but followed always by a non-common structure of numbers only.
Sub CopyValues()
Dim totArray As Variant
Dim wsSource As Worksheet
Dim wsDest As Worksheet
Dim NoRows As Long
Dim DestNoRows As Long
Dim I As Long
Dim J As Integer
Dim rngCells As Range
Dim rngFind As Range
Dim Found As Boolean
totArray = Array("TOTAAL ", "TOTAL")
Set wsSource = Worksheets("Input")
Set wsDest = Worksheets("Output")
NoRows = wsSource.Range("A65536").End(xlUp).Row
DestNoRows = 2
For I = 1 To NoRows
Set rngCells = wsSource.Range("A" & I)
Found = False
For J = 0 To UBound(totArray)
Found = Found Or Not (rngCells.Find(totArray(J)) Is Nothing)
Next J
If Found Then
rngCells.Copy wsDest.Range("B" & DestNoRows)
DestNoRows = DestNoRows + 1
End If
Next I
End Sub
To find a string with characters before/after the specified string:
You could put wildcards into the string, see this documentation.
"*TOTAL" would find Subtotal, Grandtotal etc as the asterisk wildcards any number of characters.
"*TOTAL????? would find any word with total at the end (like the example above) and with up to 5 characters after the word (as there are 5 question marks). For example: Subtotal123 or Subtotal54321
*TOTAL ????? would find Subtotal 123 or Subtotal 54321 (notice the space can be used in the string between characters/wildcards).
Using this info you should be able to adjust your Array strings to work in your situation.
To find an exact match to the specified string:
You should specify the LookAt parameter in your .find method.
e.g. rngCells.Find(totArray(J), , , LookAt:= xlWhole).
Using the LookAt function is pretty straightforward.
xlWhole means the search value must match the entire cell contents.
xlPart means the search value only has to match part of the cell
Note: In that example the After and LookIn parameters are omitted.
The LookAt parameter is the 4th parameter which is why there are blanks between the commas.
If you don't specify your parameters, Excel uses the parameters from the last search you ran either from using the .Find method via VBA or the GUI find window.
You can read more about each parameter, including the LookAt parameter in this article about the vba find method.

VBA excel: How do I compare a string array to a string?

I have a script that takes the contents of a cell, and puts the first 2 characters of the cell into a string array. I need to later compare that string array to a string, but I can't seem to get that to work. Here's what I have:
For i = 2 To 600
colStr = Sheets("smartlist").Cells(i, "A").Value
If colStr <> "" Then
ReDim charArray(Len(colStr) - 1)
For j = 1 To Len(colStr)
charArray(j - 1) = Mid$(colStr, j, 1)
Next
strArray = LCase(charArray(0)) & LCase(charArray(1))
If CStr(Join(strArray)) = CStr(Join(pwArray)) Then
Now, I've tried:
If charArray = "ab"
If Join(charArray) = "ab"
If CStr(Join(charArray)) = "ab"
I'm pretty lost at this point. Any suggestions would be welcome!
Edit: added the whole function up until I get the 'Type mismatch'
You could use Join(charArray, "") - without "" it joins the elements with space so the result of your initial try was "a b"
Firstly, you really need to clarify what you're doing. You say that later you need to check what's in the string. If that is the case, then you don't need an array, you simply need another string...
Dim chars As String
chars = Left$(cellToTest, 2)
Later you can test more simply using the InStr function, like so...
Dim loc As Integer
loc = Instr(colStr, chars)
If loc > 0 Then
...
If you want to turn this into a function on your spreadsheet you can use the following in the cells as formulas...
=LEFT(A1, 2)
=SEARCH(A3, A1)
Here's a little screen shot of what I mean...

Excel VBA: Need Workaround for 255 Transpose Character Limit When Returning Variant Array to Selected Range

I am struggling with a common problem involving an apparent Excel 255-character-limit. I encounter an error when attempting to return a variant-array from a Function to the selected range on the worksheet. When each of the cells in the Function's returning array are under 255 characters, they post to the sheet just as they should: one element appears in each cell within the selected range. However, if any element in my returning variant array is longer than 255 characters I get a Value! error. These errors are bad because I need my long elements and want to keep the data together!
Versions of this problem appear over and over again in many forums, yet I am able to find a clear simple, all-purpose solution for returning variant arrays to the selected range (not necessarily containing formulas) when the array cells exceed 255 characters. My largest elements are around 1000, but it would be better if the solution could accommodate elements up to 2000 characters.
Preferably, I want this to be implemented with a function, or lines of additional code which can be added to my function (not a subroutine). My reason for wanting to avoid subroutines: I do not want to have to hard-code any ranges. I want this to be flexible and for the output location to be dynamically based on my current selection.
Please, if you can help find a way to produce a function, which takes a Variant Array as input, and which maintains the desired array:cell 1:1 relationship, I'd appreciate it greatly.
So this function with short cells works:
Function WriteUnder255Cells()
Dim myArray(3) As Variant 'this the variant array I will attempt to write
' Here I fill each element with less than 255 characters
' it should output them if you call the function properly.
myArray(0) = "dog"
myArray(1) = "cat"
myArray(2) = "bird"
myArray(3) = "fly"
WriteUnder255Cells = Application.Transpose(myArray())
End Function
But this fuction, with cells exceeding 255 will not output.
Function WriteOver255Cells()
Dim myArray(3) As Variant 'this the variant array I will attempt to write
' Here I fill each element with more than 255 characters
' exceeding the 255-character limit causes the VALUE! errors when you output them
myArray(0) = "ThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelaxydog"
myArray(1) = "ThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydog"
myArray(2) = "ThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydog"
myArray(3) = "ThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydogThequickbrownfoxjumpedoverthelazydog"
WriteOver255Cells = Application.Transpose(myArray())
End Function
This is how you produce the output and results:
First you need to create the two modules(to insert one function into each module, paste the code from one into the respective module). To run "WriteUnder255Cells()", select an area of 4 rows x 1 column on the sheet (this where you return the module) and type "=WriteUnder255Cells()" into the formula bar (do not enter the quotes). Note these are called like array formulas, so instead of hitting (enter) to create the output, you need to hit (control + shift + enter). Repeat the same process for WriteOver255Cells() to produce the errors.
Here are some documents/forums discussions which address it. The solutions seem to be either overly specific or clunky because they evoke subroutines (which I want to avoid):
https://support.microsoft.com/en-us/kb/213841
http://www.mrexcel.com/forum/excel-questions/852781-visual-basic-applications-evaluate-method-255-character-limit.html
Excel: Use formula longer that 255 characters
VBA code error when array value exceeds 255 characters
http://dailydoseofexcel.com/archives/2005/01/10/entering-long-array-formulas-in-vba/
https://forums.techguy.org/threads/solved-vba-access-to-excel-255-char-limit-issue.996495/
http://www.mrexcel.com/forum/excel-questions/494675-255-character-cell-limit-visual-basic-applications-workaround.html
Array formula with more than 255 characters
http://www.mrexcel.com/forum/excel-questions/388250-size-limit-transferring-variant-range-excel-2007-a.html
This works for me:
Function Over255()
Dim myArray(3) As String '<<<<< not variant
myArray(0) = String(300, "a")
myArray(1) = String(300, "b")
myArray(2) = String(300, "c")
myArray(3) = String(300, "d")
'Over255 = Application.Transpose(myArray())
Over255 = TR(myArray)
End Function
'like Application.Transpose...
Function TR(arrIn) As String()
Dim arrOut() As String, r As Long, ln As Long, i As Long
ln = (UBound(arrIn) - LBound(arrIn)) + 1
ReDim arrOut(1 To ln, 1 To 1)
i = 1
For r = LBound(arrIn) To UBound(arrIn)
arrOut(i, 1) = arrIn(r)
i = i + 1
Next r
TR = arrOut
End Function
Seems like you need to return a string array and Application.Transpose doesn't do that

VBA Excel Range() with Cell argument

Why does the following not work:
Range(Cells(1,1)).Value = 3
Cells(1,1) should essentially be the same thing as using A1 right?
(I realize that I could just do Cells(1,1).Value = 3, but I'm just curious as to why it doesn't work.)
I read the MSDN entry and it shows that the first argument must be A1 style, yet something like this does work:
Range(Cells(1,1), Cells(2,3)).Value = 2
Totally confused.
When Range is used with a single parameter, the parameter is is interpreted as a range name.
Range(Cells(1,1))
is the same as using
Range(Cells(1,1).Value)
So you will get a result only is the value of Cells(1,1) is a valid range address in A1 style
Only when passed two range parameters are they interpreted as the corners of a range.
When you want to use the Cells property to specify the parameters of the range object (if I remember rightly - I've not been using VBA for some time), then you have to effectively supply two arguments.
So if you want to reference a range object that has only one cell, then you need to write:
Range(Cells(1, 1), Cells(1, 1)).value = "Hello World"
Instead of referring to a single cell like this:
Range(Cells(1,1), Cells(1,1))
You can write:
Range(Cells(1,1).Address)
For a single cell its much easier: Use the default Cells() function:
Cells(1,1) = "hello world"
or use a Sheet's Cells() function:
Dim sht as Worksheet
Set sht = Sheets("myworksheet") ' or: = Sheets(1)
sht.Cells(1,1) = "hello world"
For a range you'll have to use two params, as explained in the other answers given here. But the advantage is that you can set a whole range of fields to a value. And you can work on a sheet that isn't the 'Active one', behind the scenes. For example:
Const colRand = 4
Const colDiff = 5
Dim sht as Worksheet, rngHi As Range, rngRand As Range, rngDiff As Range
Set sht = Sheets("myworksheet") ' or: = Sheets(1)
Set rngHi = sht.Range(sht.Cells(1,1), sht.Cells(3,3)
rngHi = "hello world"
Set rngRand = sht.Range(sht.Cells(1,colRand), sht.Cells(8,colRand) ' column 4, rows 1-8
rngRand = "=RAND()"
Set rngDiff = sht.Range(sht.Cells(2,colDiff), sht.Cells(8,colDiff) ' column 5, rows 2-8
' using FormulaR1C1 in case the sheet isn't set to use that type of formula
Set rngDiff.FormulaR1C1="=RC[-1] - R[-1]C[-1]" ' on previous columnn, diff between this row and previous row
Explanation:
The Cells function receives either:
a string parameter - in which you specify the A1_And_Colon Style range
or two Cell parameters - the beginning cell of the range and the end cell.
So to set the range with 'cells' you need to give both cells divided by a comma:
Range(Cells(1,1), Cells(1,1)) = "hello world"
Range(Cells(2,2), Cells(3,4)) = "you cannot square around, but you can round a square"
Sheets(1).Cells(5,5) = "=Round(Sqrt(5))"
I'm writing this answer because I'm learning VBA and it took me the better part of three days to figure out what was happening here, and the official documentation does not discuss this topic at all. This QA is good but the information is a bit scattered, from my perspective today.
Here's what I know about using the Cells() property inside a Range() object to reference a single-cell range. Which I need to do all the time!
Given a valid ws object...
You think this will work:
ws.Range(ws.Cells(i,j))
It doesn't. You'll get Run-time error '1004': Method 'Range' of object'_Worksheet' failed.
The obvious fix, as described by #Woody_Pride is:
ws.Range(ws.Cells(i,j), ws.Cells(i,j))
Unfortunately, having to do this is absolutely infuriating, and is not actually strictly necessary.
What you actually need is, as asserted by #Willby, although the explanation as to why this is the case is actually in the answer by #chris_neilsen:
ws.Range(ws.Cells(i,j).Address)
This will also work, as suggested by #pashute (who is wrong in most parts of his explanation):
ws.Cells(i,j)
Thank you to everyone who contributed on this page; I feel like I now, finally, have the entire picture.
I know sometimes you need a range for other properties other than value. What i would do is make a function to help you:
Public Function cellRange(ws As Worksheet, rowNum As Integer, colNum As Integer) As Range
Set cellRange = ws.Range(ws.Cells(rowNum, colNum), ws.Cells(rowNum, colNum))
End Function
This way you can make cleaner code:
Set ws = ActiveWorkbook.Sheets("Sheet1")
cellRange(ws, 1, 3).Interior.Color = cellRange(ws, 1, 8).Interior.Color
When using "cells", it is required to formulate Object.cells ,
e.g. Application.cells(2,2) or activeWorksheet.cells

Excel VBA, over flow error

I am using VBA in my excel sheet and it gives me an overlfow error. When I checked I found out that it was related to data error which shows unilmited "#" character in one cell.
All values in each cell is assigned to a string variable and when this cell comes in generates an overflow error. I tried to validate this using an if condition, but whenever we check cell.value this generates an overflow error. Is there any way to fix this?
You will not get a runtime error if you just read the cell text:
s = Range("C2").Text
Debug.Print s
' returns: "###########"
If you really want to read the cell value, and not the cell text (why you would need this, I have no idea, since you're stuffing it in a String anyway) then this is a workaround, assuming the #### are caused by dates Jan 1, 10,000 AD or later.
Const MaxDateSerial As Double = 2958466
Dim s As String
Dim dbl As Double
Dim nf As Variant
' Save original number format
nf = Range("C2").NumberFormat
' Use read-safe number format to read cell content
Range("C2").NumberFormat = "General"
dbl = Range("C2").Value
' Restore original number format
Range("C2").NumberFormat = nf
If dbl < MaxDateSerial Then
s = Range("C2").Value
Else
s = "Date overflow!"
End If
If you are doing something like
Dim s as string
Dim cl as Range
...
s = cl
' or
s = cl.value
s will be set to the value as diplayed on the sheet, which includes an error
(in the form "Error <Error Code>" if that's what the sheet displays
If the underlying cell value is valid, you should be able to access if using cl.value2
If you are doing somthing like
Dim v as Variant
Dim s as string
Dim r as Range
...
Set r = <SomeRange>
v = r
...
And one or more cells in range r are an error, then Runtime Error 6 Overflow will occur
To advise further, please post details of the code, where the error occurs, cell value and cell formatting
The ############### display for dates occurs if the date serial is before 1/1/1900 (negative) or after 1/1/9999 (> 2958101) EDIT actually 31/12/9999 = 2958465
Try using the "ISERROR()" function to filter out the invalid values.
IF(ISERROR(A1),0,A1)