How to replace every existing values of a column with formula? - vba

My sheet already has data. Unfortunately, later I realized that all the values in column E should be validated and changed as necessary by calling my own user-defined function and passing the values as the function parameter. For example, say I have the following data in column E:
E1: "This is a text in (E1)"
E2: "This is a text in (E2)"
...
E7000: "This is a text in (E7000)"
Now, I want every value in column E to be changed by a formula like this:
E1: = RemoveBrackets("This is a text in (E1)")
E2: = RemoveBrackets("This is a text in (E2)")
...
E7000: = RemoveBrackets("This is a text in (E7000)")
Supposing Excel supports Regex, my problem can be solved easily. but unfortunately Excel doesn't. Could someone propose possible solutions to my problem?
Thanks in advance

1) Insert a new column "F"
2) Copy column E into F
3) Write in E1
=RemoveBrackets(F1)
4) Drag the E1 value through E7000
5) Hide column F.
Edit 1
You can do it with several passes of the Find/Replace feature:
Select the Column E before each PASS.
PASS 1
Find: <"This is a text in>
Replace with: <RemoveBrackets("This is a text in>
PASS 2
Find: <)">
Replace with: <)")>
PASS 3
Find: <RemoveBrackets(>
Replace with: <=RemoveBrackets(>
Edit 2
VB Regex substitute string function can be used from Excel.
You may dowload a toolpack such as Morefunc which supports a REGEX.SUBSTITUTE udf, or you could do your own udf using THIS as guideline.
I am posting here the code from the second reference, just for link independence:
Public Function SearchNReplace1(Pattern1 As String, _
Pattern2 As String, Replacestring As String, _
TestString As String)
Dim reg As New RegExp
reg.IgnoreCase = True
reg.MultiLine = False
reg.Pattern = Pattern1
If reg.Test(TestString) Then
reg.Pattern = Pattern2
SearchNReplace1 = reg.Replace(TestString, ReplaceString)
Else
SearchNReplace1 = TestString
End If
End Function
Please read the full article, as you should turn on the Microsoft VBScript Regular Expressions 5.5 option in Excel first.
HTH

Similar to belisarius' method, but doesn't leave a trace:
Insert column F
Insert into F1 the value =RemoveBrackets(F1)
Copy down through F7000.
Copy column F
Right click cell E1, Paste Special, choose "Values".
Delete column F

Related

VBA: using index and match with two columns as criterias (INCOMPATIBLE VARIABLE ERROR) [duplicate]

So in Excel, we know it's possible to test against multiple criteria via concatenation, like this:
MATCH(criteria1&criteria2, Range(), 0)
where criteria1 and criteria2 are 2 separate criteria.
I'm trying to automate this thing in Excel VBA, like this:
WorksheetFunction.Match(criteria1 + "&" + criteria2, Range(), 0)
My question is, how do I replicate the same concatenation of criteria with the ampersand, in VBA form? In the version above, Excel keeps telling me it can't use the Match function of the WorkSheetFunction class, which I'm attributing to the failed concatenation attempt above. Any suggestions or advice would be greatly appreciated.
Oh, and here's a link to a Microsoft Knowledge Base article about using multiple criteria in MATCH(): http://support.microsoft.com/kb/59482
EDIT: I realized I wasn't putting 2 ranges to correspond with my 2 criteria. The problem is I don't know how to concatenate 2 ranges, because mine are in the form:
Range(Cells(1,columnIndex),Cells(rowCount,columnIndex))
as opposed to A1:A200. Any ideas on how to convert, or to concat the ranges in their current form?
This works:
Sub dural()
crit1 = "find "
crit2 = "happiness"
N = Application.WorksheetFunction.Match(crit1 & crit2, Range("A1:A10"), 0)
MsgBox N
End Sub
with, say A3 containing:
find happiness
EDIT#1:
Consider the case of multiple criteria in several columns. For example:
and we want VBA to retrieve the name of a small, black, dog
without VBA in a worksheet cell we can use:
=INDEX(D1:D100,SUMPRODUCT(--(A1:A100="dog")*(B1:B100="small")*(C1:C100="black")*ROW(1:100)),1)
to get the name Oscar
we can use the same formula in VBA
Sub luxation()
Dim s As String, s2 As String
s = "INDEX(D1:D100,SUMPRODUCT(--(A1:A100=""dog"")*(B1:B100=""small"")*(C1:C100=""black"")*ROW(1:100)),1)"
s2 = Evaluate(s)
MsgBox s2
End Sub
Doesn't readily map to a VBA implementation, but you can cheat a bit using Evaluate:
Sub Tester()
Dim v1, v2, f
v1 = "y"
v2 = 11
Sheet1.Names.Add Name:="X", RefersTo:=v1
Sheet1.Names.Add Name:="Y", RefersTo:=v2
f = "MATCH(X&Y,$A$2:$A$5&$B$2:$B$5, 0)"
Debug.Print Sheet1.Evaluate(f)
End Sub
or skipping the names:
Sub Tester2()
Const F_TEMPL As String = "MATCH(""{V1}""&""{V2}"",$A$2:$A$5&$B$2:$B$5, 0)"
Dim v1, v2, f
f = Replace(F_TEMPL, "{V1}", "x")
f = Replace(f, "{V2}", 12)
Debug.Print Sheet1.Evaluate(f)
End Sub
You still need to send the MATCH argument body as a string. The '+' does not concatenate.
WorksheetFunction.Match(criteria1 & "&" & criteria2, Range(), 0)
Should concatenate the two values and execute the match.

SSIS - Conditional Split when rows are not null

I have .xlsx sheet where data starts from A1:AB199. I am trying to extract data from Row A6:AB48 and ignore the rest.
Started creating a Conditional Split so SSIS package can start from Row A6 and end at Row AB48 but failing. Please guide
Try this, In your Data Flow task, you will need to set the "OpenRowset" Custom Property of your Excel Connection
Or
Another MSDN Link
1 - Excel Source -> Variables -> In Data Access Mode select "Table name or view name variable"
2- In the variable name select a variable that you had made before "MyVar"
3- Go To variable select "MyVar" and type "TabName$A12:H125"
Before conditional split add a script component with one output column of type DT_BOOL . In my example i assume that is named OutColumn.
In the script window add the following Code:
Private m_intRowCounter as integer = 0
Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)
m_intRowCounter += 1
if m_intRowCounter >= 6
Row.OutCOlumn = True
Else
Row.OutCOlumn = False
End If
End Sub
In the conditional split split row on OutColumn : if true take rows to destination
Hope it helps

Selecting every Nth row, Excel. Replace with nothing or original cell content

I've got an Excel sheet with my variables listed in column E and their values listed in column G
I would like to test if E contains the word "text" (my variable). If so then I want to replace the corresponding cell in column G with "This is my successful if statement text".
If not -- I want the cell to either be left alone (impossible in excel) or keep the value it originally had (I think the issue is its populated with text not numbers).
So far ive tried
=if(e2="text", "Replace with this", G2)
as well as
=if(e2="text", "replace with this", "")
The top returns a number while the bottom returns an empty cell which deletes the contents I had there.
Any suggestions? I think this can be done with VB but that's out of my league.
The proper way to solve this is as so.
In column H (or any that doesn't contain any information) place the formula
=IF(E2 = "text", "This is the true part", G2) and drag down.
This will test E2 for the word "text" and then replace with "this is true.." If the conditions are not met, the original text from G2 is pulled into the new column.
Once this is complete, the desired results should have taken effect. You can then copy the row and use "Paste Special" and select "Values" from the pop up menu to paste in your new data. Selecting Values allows the user to paste the actual field data, not the formula that generated it!
Try this.
Sub g()
Dim ws As Worksheet
Dim lastRow As Long
Set ws = ThisWorkbook.Worksheets("Sheet1") 'change sheet name as applicable
lastRow = ws.Cells(ws.Rows.Count, "E").End(xlUp).Row
For i = 1 To lastRow
With ws
If .Cells(i, 5) = "text" Then
.Cells(i, 7) = "The text you want"
End If
End With
Next
End Sub
It seems like you are trying to get four values from column E that you want to parse (cut up) and place in Column G.
By creating four parses { =mid(e2,16,10), =mid(e3, 9, 15), =mid(e4,5,3), =mid(e5,10,22) } in cells G2, G3, G4, and G5, respectively, you can select the block of four G cells (G2:G5), select the block at the bottom right, and drag it down throughout the file.
Optionally, you can use modulo math and case statements to loop through the file and perform the required function at each point:
myCount = 0
myLoop = 0
endMyLoop = false
range("G2").activate
do
myLoop = myCount mod 4
select case myLoop
case 0
code for description_tag
case 1
code for title_tag
case 2
code for headline
case 3
code for text
end select
if activecell.value = "" then endMyLoop = true
loop until (endMyLoop = true)
You stated that every fourth row the value in E is text. So, it should just be a matter of copying the formula every fourth row or performing your function every fourth iteration (modulo returns the remainder) in the G column.
One other option would be to nest your if loops (=if(e2="text","Its text",if(e2="title_tag","Its a title",if(e2="headline","Its headline","Its description")))) to account for the four different options. Of course you would fill the text with the function that you actually want to perform.

Return a list of column headers across a row when cells have text

I want to get a list of column headers for each cell that contains a text value.
Eg.
A--------------B-------------C-------------BC (desired output)
1 Header1 Header2 Header3
2 M T Header1, Header3
3 T MT Header1, Header2
4 TMW Header2
In the final product I want to use two final columns with formulas listing headers from cells with values across 9 columns and a second with the other 40 odd columns.
I have the vague notion that I might need to use INDEX, MATCH and IF functions - but as a novice have no idea how to string them together coherently.
Here I will make use of VBA's Join function. VBA functions aren't directly available in Excel, so I wrap Join in a user-defined function that exposes the same functionality:
Function JoinXL(arr As Variant, Optional delimiter As String = " ")
JoinXL = Join(arr, delimiter)
End Function
The formula in D2 is:
=JoinXL(IF(NOT(ISBLANK(A2:C2)),$A$1:$C$1&", ",""),"")
entered as an array formula (using Ctrl-Shift-Enter). It is then copied down.
Explanation:
NOT(ISBLANK(A2:C2)) detects which cells have text in them; returns this array for row 2: {TRUE,FALSE,TRUE}
IF(NOT(ISBLANK(A2:C2)),$A$1:$C$1&", ","") converts those boolean values to row 1 contents followed by a comma delimiter; returns the array {"Header A, ","","Header C, "}.
JoinXL joins the contents of that array into a single string.
If you want to use worksheet functions, and not VBA, I suggest returning each column header in a separate cell. You can do this by entering a formula such as:
This formula must be array-entered:
BC: =IFERROR(INDEX($A$1:$C$1,1,SMALL((LEN($A2:$C2)>0)*COLUMN($A2:$C2),COUNTBLANK($A2:$C2)+COLUMNS($A:A))),"")
Adjust the range references A:C to reflect the columns actually used for your data. Be sure to use the same mixed address format as in above. Do NOT change the $A:A reference, however.
Then fill right until you get blanks; and fill down as far as required.
You can reverse the logic to get a list of the "other" headers.
To array-enter a formula, after entering
the formula into the cell or formula bar, hold down
ctrl-shift while hitting enter. If you did this
correctly, Excel will place braces {...} around the formula.
If you really need to have the results as comma-separated values in two different columns, I would suggest the following User Defined Function.
To enter this User Defined Function (UDF), alt-F11 opens the Visual Basic Editor.
Ensure your project is highlighted in the Project Explorer window.
Then, from the top menu, select Insert/Module and
paste the code below into the window that opens.
To use this User Defined Function (UDF), enter a formula like
=Headers($A2:$BA2,$A$1:$BA$1,True)
or, to get the headers that do NOT contain text:
=Headers($A2:$BA2,$A$1:$BA$1,FALSE)
in some cell.
=====================================================
Option Explicit
Function Headers(rData As Range, rHeaders As Range, Optional bTextPresent As Boolean = True) As String
Dim colHeaders As Collection
Dim vData, vHeaders
Const sDelimiter As String = ", "
Dim sRes() As String
Dim I As Long
vData = rData
vHeaders = rHeaders
Set colHeaders = New Collection
For I = 1 To UBound(vData, 2)
If (Len(vData(1, I)) > 0) = bTextPresent Then colHeaders.Add vHeaders(1, I)
Next I
ReDim sRes(1 To colHeaders.Count)
For I = 1 To colHeaders.Count
sRes(I) = colHeaders(I)
Next I
Headers = Join(sRes, sDelimiter)
End Function
==========================================
You should probably add some logic to the routine to ensure your range arguments are a single row, and that the two arguments are of the same size.

User input requirements for String values

Alright, I am trying to create a user defined function that will accept one character input, and then return a String. Although I couldn't get the Char data type to work for VBA (not sure why?) I was able to get it working fine if I inputted the single character value as a String.
Currently, when the UDF is running within Excel, it will work as long as quotes are placed around the String input, as shown:
=tradeClass("o")
that will work and return the correct result. But what I really would like to do is be able to write the Excel function in this manner:
=tradeClass(o)
I wrote out code that will concatenate "" onto the ends of my user input:
Public Function tradeClass(class As String)
Dim result As String
Dim before As String
Dim after As String
before = """"
after = """"
class = before & class & after 'my attempt to concatenate " on either side of the class input
Select Case LCase(class)
Case "s"
result = "Sale"
Case "r"
result = "Redemption"
Case "i"
result = "Exchange In"
Case "o"
result = "Exchange Out"
Case "x"
result = "Ignore"
Case "k"
result = "Settle"
Case "m"
result = "Transfer"
Case "w"
result = "ML PR3 Redemption (No longer in use)"
Case Else
result = "Invalid Entry"
End Select
tradeClass = result
End Function
It returns a #VALUE! error in Excel, so I am starting to think that I will always have to enter quotation marks with my character. Is this the case?
I can't imagine what compelling reason you have to want to do this. If you were truly determined, there is a hack/workaround/kludge that will allow this to work.
I strongly advise you not to use this, but you asked a question to which I have an answer. So here goes:
When you pass an unquoted string of character(s) to a function in Excel, it assumes that it is a reference to another cell. This is obvious in a function call such as =tradeClass(A1). That function will pass the value of the cell A1 to the function tradeClass.
Excel also supports naming cells to make formulas easier to follow. For example, you could assign the name "StartYear" to cell A1. So instead of using =DATE(A1, 1, 1) you could use =DATE(StartYear, 1, 1) which will be easier to maintain.
Now, in your case, we can abuse this power and name a bunch of cells s, r, i, o, x, k, m, and w. In the cell named s we would enter the letter "s" as the cell's value and so on. So then when you call =tradeClass(o), Excel will look up the cell named o and get its value (which we set to "o") and pass the value "o" of the cell named o to your tradeClass function.
This is a dreadful abuse of the cell-naming capabilities of Excel and violates all sorts of good programming practice. But ask, and you shall receive.
DISCLAIMER: Please do not actually use this.
One final note: When, someday, someone comes along and changes the value of the cell named o to the letter "s", please refer to the above disclaimer.
Unfortunately, if you want this function to work on user input as specified, you're going to need to pass in with quotes. Try out a built-in Excel function, for example:
=LEN(String)
vs.
=LEN("String")
The second one gives you 6, while the first one gives you an error.
However, your code would work nicely if the trade classes you're after are in their own column, like this:
Public Function tradeClass(Str As Variant)
Str = CStr(Str) 'force the variant to a string
Select Case LCase(Str)
Case "s"
result = "Sale"
Case "r"
result = "Redemption"
Case "i"
result = "Exchange In"
Case "o"
result = "Exchange Out"
Case "x"
result = "Ignore"
Case "k"
result = "Settle"
Case "m"
result = "Transfer"
Case "w"
result = "ML PR3 Redemption (No longer in use)"
Case Else
result = "Invalid Entry"
End Select
tradeClass = result
End Function
I know it’s an old question but got the same error and found the reason and something like this worked for me: you shall use Public Function tradeclass(class) and then class = class.address. Hope this helps!