I'm trying to build a function to return the end string/cell value of an xlFillSeries. Is there any way to do it without actually writing to the worksheet and then selecting last cell? I want to avoid manipulating the worksheet/workbook
.
Here is the code to generate the series:
Dim SeqStart As String, SeqInt As Integer
SeqStart = "XYZ100"
SeqInt = 42 ' Function should return XYZ141
With Range("A1")
.Value = UCase(SeqStart)
If SeqInt > 1 Then
.AutoFill Destination:=Range("A1").Resize(SeqInt), Type:=xlFillSeries ' Will cause error if only 1 sample sequence
End If
End With
I want to utilize XlFillSeries as it handles odd data well, Eg: If my SeqStart = A1B100 then I can't utilize Regex to strip this down to just numbers, perform math, and then put it back together as there is a B in the middle of the string. I do know the series will/should always end in numbers, but I've struggled a bit to strip just the numeric portion from the right hand of the string without knowing string length and or mix of alphanumeric oddities.
So I guess my question could be answered by figuring out how to strip numbers from right side of string and then doing math and putting string back together. The numbers are what increments.
Or, I would just utilize XlFillSeries but without actually writing to the workbook. Currently I did just set it up so that it writes to a "temp sheet" and then captures the last cell and deletes the temp sheet, but I wondered if there was a better way.
Specifically talking about XlFillSeries there is no way to utilize it without writing to a Range which must be "real cells". Therefor the best method is to utilize a "temp sheet" and return the last cell. It may be possible to utilize functions to strip numbers from right hand side of string and then re-build string, but I trust XlFillSeries more and have resigned to just using a "temp sheet".
Here is my function:
Note: There are some custom functions that I wont include, but you can guess what they do based on the name!
Public Function EndOfXlFillSeries(SeqStart As String, SeqInt As Integer) As String
Dim DestSheet As Worksheet
WorksheetCreateDelIfExists ("XLFillSeriesTmp")
Set DestSheet = Worksheets("XLFillSeriesTmp")
With DestSheet.Range("A1")
.Value = UCase(SeqStart)
If SeqInt > 1 Then
.AutoFill Destination:=DestSheet.Range("A1").Resize(SeqInt), Type:=xlFillSeries ' Will cause error if only 1 SeqInt
Else
EndOfXlFillSeries = SeqStart
End If
End With
Dim lRow As Integer
lRow = lRowOfCol(1)
EndOfXlFillSeries = DestSheet.Range("A" & lRow).Value
Call WorksheetDelete(DestSheet)
End Function
Related
The main problem started when I wanted to "convert to number" by the green triangle (I know I can do it by hand, but there are a lot of cells like that and in the future I only want to use code).
So I wanted to do it by code, and I came across with this code that helps, but I have a problem with the number format which removes the decimal numbers.
Sub Valor3()
Dim LastRow As Long, i As Long
LastRow = Sheets("Hoja3").Range("A" & Rows.Count).End(xlUp).Row
'Sheets("Hoja3").Range("A1:A" & LastRow).NumberFormat = "# ##0,00"
For i = 1 To LastRow
If Val(Sheets("Hoja3").Range("A" & i).Value) <> 0 Then _
Sheets("Hoja3").Range("A" & i).Formula = _
Val(Sheets("Hoja3").Range("A" & i).Value)
Next i
End Sub
I've been trying many formats but none of them seems to help.
It might be because here we use the comma as a decimal separator and there is no miles separator.
What number format would help me?
The issue is that you use Val function in combination with a non-us-english decimal separator, which is not a proper solution to your issue.
The Val function recognizes only the period ( .) as a valid decimal separator. When different decimal separators are used, as in international applications, use CDbl instead to convert a string to a number.
Source: Microsoft documentation Val function.
Since the Val function does not convert a text into a value but extracts
The Val function only works with a dot . as decimal separator.
Example:
Val("2.55") 'will return 2.55 as number
Val("2,55") 'will return 2 as number (because it cuts off all text and the comma is not considered as decimal separator)
To get rid of the green triangle and convert a number that is saved as text into a real number properly, use the following:
Option Explicit
Public Sub ConvertNumberAsTextIntoRealNumber()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Hoja3")
Dim LastRow As Long
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
With ws.Range("A1", "A" & LastRow)
.NumberFormat = "# ##0.00" 'set your desired number format
.Value = .Value 'this will in most cases already convert to real numbers.
End With
'But if your numbers are hard coded to text and begin with a `'` you need the following additionally:
Dim iRow As Long
For iRow = 1 To LastRow
With ws.Cells(iRow, "A")
If IsNumeric(.Value) Then 'can the value be interpreted as a number
If .Value <> 0 Then 'is the value not zero
.Value = CDbl(.Value) 'then convert it into a real number
End If
End If
End With
Next iRow
End Sub
I know you are looking for VBA solution, but here's a small Excel trick that you might find useful:
Enter 1 (numeric value) somewhere in the file and copy it:
Select your range (A1:A6) and go to Paste > Paste Special > select Multiply:
The final result is all your text values being converted to numbers:
The same trick will work with other combinations, e.g. Operation: Add while having 0 copied, etc.
I've created a VBA Macro to look at a string of input text in the cell E3, split it into individual characters and then VLookup those characters against a table of individual character pixel widths, which is added to the code using a named range, "pw_Table".
The pixel-widths for each letter are then summed and displayed in a cell below the text input box - "Cells(4,5)". Hitting return is meant to show the combined pixel-width total for the complete string.
The problem is that it is not being case sensitive and is using the same VLookup value for both upper and lower case characters.
All the manuals I've seen say VBA is case sensitive on VLookup, and all I can find are ways to get around this.
For my issue, however, the VLookup must be case sensitive to make sure I get the correct pixel width for each letter, for example, "c" is 9 pixels wide, "C" is 13.
I have tried reordering the upper and lower case characters in the table to see if that made a difference, but it only uses the first values it encounters for each letter of the alphabet, whether they be upper- or lower-case.
I thought that I might use INDEX, MATCH, and EXACT, but couldn't see how to implement that in VBA.
This is the Macro code ...
Private Sub ReadCharacter()
cell_value = ThisWorkbook.Sheets("Pixel-widths").Range("E3")
Character_Value = 0
For rep = 1 To Len(cell_value)
Character = Mid(cell_value, rep, 1)
On Error GoTo MyErrorHandler
Character_Value = Application.WorksheetFunction.VLookup(Character, [pw_Table], 2, 0)
Pixel_Width = Pixel_Width + Character_Value
MyErrorHandler:
Character_Value = 10
Resume Next
Next rep
Cells(4, 5) = Pixel_Width
End Sub
I had some issues with numbers, with VBA reporting Run-time Error 1004, but I bodged this by adding an error trap because all the numerals from 0-9 are 10 pixels wide.
I simply can't see why VBA is breaking its own rules.
Vlookup isnt case sensitive.
ive found this function that "simulates" a vlookup case sensitive.
Function CaseVLook(FindValue, TableArray As Range, Optional ColumnID As Integer = 1) As Variant
Dim xCell As Range
Application.Volatile
CaseVLook = "Not Found"
For Each xCell In TableArray.Columns(1).Cells
If xCell = FindValue Then
CaseVLook = xCell.Offset(0, ColumnID - 1)
Exit For
End If
Next
End Function
to use it just call it CaseVLook(F1,A1:C7,3)
more information in here
https://www.extendoffice.com/documents/excel/3449-excel-vlookup-case-sensitive-insensitive.html
good luck
Here's another way...
Character_Value = Evaluate("INDEX(" & Range("pw_Table").Address(, , , True) & _
",MATCH(TRUE,EXACT(INDEX(" & Range("pw_Table").Address(, , , True) & ",0,1),""" & Character & """),0),2)")
Hope this helps!
I'm trying to make a formula that takes account codes that will be listed in Column A and make a string of them, separated by "^."
E.g., If Column A has
A
1111
12345
2222
The result will be: 1111^12345^2222 as a single cell's entry
However, I don't always know ahead of time how many values will be in column A., And if there's only a few, I can't have the trailing ^^^^^^^^^^'s. Also, the account codes aren't always the same # of digits.
I have a rough version of it done with a ton of embedded If statements, but this is clunky. I also could probably do it via macro, but I'm trying to avoid. Is there a minimalist way to code this using native Excel functions, or should I just accept that I have to send out a macro-enabled workbook?
Here's a VBA solution if you are interested:
Function Concat(rng As Range) As String
Dim i As Long
Dim iCount As Long
iCount = rng.Cells.Count
For i = 1 To iCount
If Not i = iCount Then
Concat = Concat & Cells(i, rng.Column) & "^"
Else
Concat = Concat & Cells(i, rng.Column)
End If
Next i
i = 0
iCount = 0
End Function
I'm looking for a simple Excel VBA or formula that can convert an entire row in Excel from 'number stored as Text' to an actual Number for vlookup reasons.
Can anyone point me in the right direction?
Better Approach
You should use INDEX(MATCH) instead of VLOOKUP because VLOOKUP behaves in an unpredictable manner which causes errors, such as the one you're presumably experiencing.
INDEX ( <return array> , MATCH ( <lookup value> , <lookup array> , 0) )
Using 0 as the last argument to MATCH means the match must be exact
Here is some more in-depth information on INDEX(MATCH)-ing
Further
Add zero +0 to convert a value to a number.
This can be (dangerously) extended with IFERROR() to turn non-numeric text into a zero:
=A2+0
=IFERROR(A2+0,0)
For the inverse, you can catenate an empty string &"" to force the value to be a string.
Notes
If 0 is not used as the last argument to MATCH, it will find all sorts of unexpected "matches" .. and worse, it may find a different value even when an exact match is present.
It often makes sense to do some extra work to determine if there are duplicates in the MATCH lookup column, otherwise the first value found will be returned (see example).
Help with MATCH comes from here, notably the matching logic the 3rd argument controls.
This should work if you add it before your vlookup or index/match lines:
Sheets("Sheet1").UsedRange.Value = Sheets("Sheet1").UsedRange.Value
I did find this, but does anyone have a formula as well?
Sub macro()
Range("F:F").Select 'specify the range which suits your purpose
With Selection
Selection.NumberFormat = "General"
.Value = .Value
End With
End Sub
http://www.ozgrid.com/forum/showthread.php?t=64027
Try this:
Sub ConvertToNumber()
Application.ScreenUpdating = False
Dim cl As Range
For Each cl In Selection.Cells
cl.Value = CInt(cl.Value)
Next cl
Application.ScreenUpdating = True
End Sub
To use it, simply select the relevant block of cells with the mouse, and then run the macro (Alt+F8 to bring up the dialogue box). It will go through each cell in the selected range and convert whatever value it holds into a number.
I wrote a custom vlookup function that doesn't care about data formats. Put this into a module in VBA and use = VLOOK instead of = VLOOKUP
Public Function VLook(sValue As String, rDest As Range, iColNo As Integer)
' custom vlookup that's insensitive to data formats
Dim iLastRow As Long
Dim wsDest As Worksheet
Set wsDest = Sheets(rDest.Parent.Name)
iLastRow = wsDest.Range(wsDest.Cells(100000, rDest.Column).Address).End(xlUp).Row
If iLastRow < rDest.Row + rDest.Rows.Count Then
For X = rDest.Column To rDest.Column + rDest.Columns.Count
If wsDest.Cells(100000, X).End(xlUp).Row > iLastRow Then iLastRow = wsDest.Cells(100000, X).End(xlUp).Row
Next X
End If
sValue = UCase(Application.Clean(Trim(sValue)))
For X = rDest.Row To iLastRow
If UCase(Application.Clean(Trim(wsDest.Cells(X, rDest.Column)))) = sValue Then
VLookDM = wsDest.Cells(X, rDest.Column + iColNo - 1)
Exit For
End If
Next X
End Function
The easiest way I can think of is using the built-in function =VALUE(TEXT_TO_CONVERT_TO_STRING).
I ALMOST got my code working but there are still two things wrong with it (two major things anyway).
1) The absolute cell ref. is not working as it does in Excel. I want for example $A5 but instead of changing to A6 A7 etc., it stays A5 throughout the loop.
2) There is a third column that I need to skip over. I only need my loop to write to columns under VOL and CAP, not %UTIL. How can I tell my loop to skip over $UTIL?
Option Explicit
Dim myRange As Range
Function numberOfRows() As Integer
Debug.Print ("Start test")
ThisWorkbook.Worksheets("LCI").Range("A9").Select
Set myRange = Range(Selection, Selection.End(xlDown))
Debug.Print ("Rows: " & myRange.Rows.Count)
numberOfRows = (myRange.Rows.Count)
End Function
Function numberOfColumns() As Integer
Debug.Print ("Start test")
ThisWorkbook.Worksheets("LCI").Range("B8").Select
Set myRange = Range(Selection, Selection.End(xlToRight))
Debug.Print ("Columns: " & myRange.Columns.Count)
numberOfColumns = (myRange.Columns.Count)
End Function
Sub TieOut(ByVal numberOfRows As Integer, ByVal numberOfColumns As Integer)
Dim i As Integer 'i is row
Dim j As Integer 'j is column
For i = 1 To numberOfRows 'Loop over rows
For j = 1 + 2 To numberOfColumns 'Loop over columns
ThisWorkbook.Worksheets("Loop").Select
With ThisWorkbook.Worksheets("Loop")
**.Cells(i + 3, j + 1).Value = "=INDEX('ZAINET DATA'!$A$1:$H$39038,MATCH(Loop!B$2&TEXT(Loop!$A4,""M/D/YYYY""),'ZAINET DATA'!$C$1:$C$39038,0),4)"
.Cells(i + 3, j + 2).Value = "=INDEX('ZAINET DATA'!$A$1:$H$39038,MATCH(Loop!B$2&TEXT(Loop!$A4,""M/D/YYYY""),'ZAINET DATA'!$C$1:$C$39038,0),5)"**
End With
Next j
Next i
End Sub
Sub Test()
Dim x As Integer
Dim y As Integer
x = numberOfRows()
y = numberOfColumns()
Call TieOut(x, y)
End Sub
Where have you defined it? Is it part of a BAS module?
EDIT: Put Option Explicit as the first line of BAS module & compile (Debug menu -> Compile).
You will see that there are compilation errors.
Remove Dim myRange As Range from Macro1 & Macro2.
Put it at the top of the BAS module (after option explicit)
Note: If you have a variable defined as part of a SUB, other SUB/Functions won't be able to use it. For TieOut to use myRange, it has to be defined at a scope where it can be used by all SUBs.
Also, Macro1 should run first - which assigns the value to MyRange
(i.e. Set MyRange = .....)
If Macro1 is not run, MyRange will hold no value & hence there will be runtime error when your code tries to read the property (MyRange.Rows.Count).
Please take some time to read about Scoping of variables.
A variable needs to hold some value, before you try to read from it.
This is a great example to learn what 'scope' is. You declare (or bring into existence) a variable like the range you're trying to make. It lives inside the macro (or sub procedure) that you made. However, when the sub procedure is finished, your variable no longer has a place to live and gets evicted (dropped out of your computer's memory).
Unfortunately the way your coded your macros will not work the way you are hoping they work. Your myRanges will die everytime they reach an End Sub.
Also when passing arguments (your byvals) to another sub procedure (in this case your TieOut) you must provide the right number of arguments. Your TieOut procedure currently requires two. You cannot pass one and then the other. The correct way would look something like this:
Call TieOut(myRange.Rows.Count, myRange.Columns.Count)
Also you are trying to call a procedure named TieOut2. Not sure if thats a typo, but getting procedure names right is important.
VBA is very powerful and worth learning in my opinion. You look like you are scratching the surface. I would definitely search for some VBA tutorials online. Focus on calling procedures, variable declaration, and scope and I guarantee you will be able to solve your problem :D