excel formulaR1C1 char length - excel

Visual Basic in Excel is pushing a part of the formula below on a second line. How do i keep it on one line or make it work on multiple lines?
ActiveCell.FormulaR1C1 = "=IF(ISNUMBER(SEARCH(""*DUPLICATE*"",RC[+3])),""Duplicate"",IF(ISNUMBER(SEARCH(""*ABBREV*AM or PM*"",RC[+3])),""Prohibited Abbreviation"",IF(ISNUMBER(SEARCH(""*ABBREV*>*<*"",RC[+3])),""Prohibited Abbreviation"",IF(ISNUMBER(SEARCH(""*ABBREV*Q*"",RC[+3])),""Prohibited Abbreviation"",IF(ISNUMBER(SEARCH(""*ABBREV*U*IU*"",RC[+3])),""Prohibited Abbreviation"",IF(ISNUMBER(SEARCH(""*Out of Stock*"",RC[+3])),""CMOP Out of Stock"",IF(ISNUMBER(SEARCH(""*SIG TOO LONG*"",RC[+3])),""Sig Too Long To Process"",IF(ISNUMBER(SEARCH(""*CMOP STOC*"",RC[+3])),""Quantity"",IF(ISNUMBER(SEARCH(""MISSPELLIN*"",RC[+3])),""Misspelling"",IF(ISNUMBER(SEARCH(""*MANUF*B*ORDER*"",RC[+3])),""Manufacturer'S Backorder"",IF(ISNUMBER(SEARCH(""*EXPIRED ADDRES*"",RC[+3])),""Expired Address"",IF(ISNUMBER(SEARCH(""*NOT STOCKED*LOW USAGE*"",RC[+3])),""Not Stock-Low usage"",IF(ISNUMBER(SEARCH(""*PRODUCT D*C*"",RC[+3])),""Product Discontinued"",IF(ISNUMBER(SEARCH(""*REFRIG*PO BOX*"",RC[+3])),""Refrig Item/PO Box Address"",IF(ISNUMBER(SEARCH(""*CORRECT*RESUBMIT*"",RC[+3])),""Correct Qty & Resubmit"","" "")))))))))))))))"""

You can split formula text across lines in the VBA editor using carefully-placed quotes, underscores and ampersands:
Option Explicit
Sub Test()
ActiveCell.FormulaR1C1 = "=IF(15>10, " & _ '<~ quote, ampersand and underscore
"12345, " & _
"67890)"
End Sub
That being said, ActiveCell can be tricky, and the formula you're writing out is... complex. Could you perhaps design a Select...Case statement in your design to result in a more readable experience for folks who might be maintaining your code?

Related

Selecting cell in Excel VBA used to work but now generates Run-time error '1004': Method 'Range' of object '_Global' failed

The simplified sub below shows line XX1 started to fail yesterday with the above error message. I have tried it on another machine and it fails at the same point.
This code has run hundreds of times, albeit with frequent minor updates. I use this kind of method for selecting a range quite frequently and it usually works fine. It's code that I've written for my own use at work, but aiming to eventually share it with colleagues (for execution and possible ownership). It's part of a 2000-line VBA process.
I've included an earlier fragment of code with a similar line 'xx0' that works fine.
I've found that line XX1 works if I put in an arbitrary selection task beforehand like this: Range("A1").Select
Also, as a test I entered line XX2 and that works fine if I skip over line XX1.
Worse, after experiencing the error, the code continues to run (apparently normally) and then at a later point, it crashes catastrophically: Excel shuts down completely with no warning or message.
I can see that lines xx0 and xx1 are both giving Excel a task to create an address by appending a 'Long' variable to a string like "j2:j" and I guess this is not good practice (it kind of undermines the use of Option Explicit and my Dim statements), but I'm not sure how best to fix it (considering my code contains many subs / 2000 lines and is full of this kind of structure).
Option Explicit
Sub AlignTables()
Dim LastRow As Long
Dim RefColX As Integer
Sheets("shMAIN").Select
LastRow = Cells(999999, 1).End(xlUp).Row
RefColX = Rows("10:10").Find(What:="x1", LookAt:=xlWhole, MatchCase:=False).Column
'Sort shMAIN
Range("c11:c" & LastRow).CurrentRegion.Select
Selection.Sort Header:=xlYes, Key1:=Cells(10, RefColX), Order1:=xlDescending, Key2:=Range("c10"), Order2:=xlAscending
'Refresh index column
Range("c11:c" & LastRow).Select 'Line XX0
Selection.FormulaR1C1 = "=ROW()"
Selection = Selection.Value
'Prepare sort key in ShCleanData column J
Sheets("ShCleanData").Select
LastRow = Cells(999999, 1).End(xlUp).Row 'This sets LastRow to value 6981
Range("j2:j" & LastRow).Select 'Line XX1
Range("j2:j" & "6981").Select 'Line XX2
'(subsequent lines populate the column etc)
End Sub
One option could be to change all my referencing to style YY:
Range(Cells(2,10), Cells(LastRow, 10)).Select 'Style YY
Range("j2:j" & LastRow).Select 'Style XX (easier to follow)
... but I find style XX easier to follow (and easier to explain to people with no VBA knowledge who may need to run and support my code).
KEY QUESTIONS:
Would declaring LastRow as Variant (instead of Long) be a robust
solution to this? [Not only to maintain the 'readable' style, but
also to simplify modifying all my subs]
Or should I go through my code removing Range Selections of type XX and changing them all to style 'YY'?
Or is there some other better solution?
One other strange observation that may be relevant: I have a VBA Function: jStop ("Run this section stepwise if you're processing data of type XX") I use this function throughout my code with different messages. The jStop function simply displays the string in a msgbox together with 'Click OK to continue or Cancel to Stop' and handles the user's request to stop (or not). It has been working for many months, but yesterday just before I encountered the 'XX1' issue, I noticed that this function was ignoring the text argument (it behaved like jstop ("") ) ... perhaps this gives a clue about what's behind the XX1 issue? This odd behaviour of jStop did not persist after a reboot.

Odd behaviour by automatically changing color of certain characters in a cell

I'm facing a odd behavior by applying different colours within one cell via VBA.
In my case there are hundrets of cells within one column, showing different work-packages.
My vba code exaclty does what it should do, by coloring identified strings (respecively work packages) via looping through the cells and identifiying each work package via RegExp.
Here there is one extract that is doing the coloring job:
Set objRegex = CreateObject("vbscript.regexp")
With objRegex
.Global = True
.Pattern = suchmuster
If .test(objWks_myTable.Cells(row_myTable, 20).Value) Then
Set RegMC = .Execute(objWks_myTable.Cells(row_myTable, 20).Value)
For Each RegM In RegMC
objWks_myTable.Cells(row_myTable, 20).Characters(RegM.FirstIndex + 1, RegM.Length).Font.Color = vbOrange
Next
End If
End With
The issue appears as soon as I double click the cell after my makro run.
Then without any recognizable pattern, some characters are shown in a different color (mostly not only one character but a connected bunch of). In the picutre, the first cell shows the colours after my vba run, the second cell shows how it will immediately look like, if i double click it.
If I leave the edit mode via Escape, the original vba set colors will stay, If I leave the edit mode via Return, the undefined changes happen.
There are no formats nor format conditions set within the cells.
I really need somebodys help here. Would be great to find a solution!
Many Thanks !
This picture should show the issue:
Picture of the issue
I've found the issue.
First I tried also Instr instead of using a RegExp but the issue didn't disappear.
So I was investigating in my code that writes the strings into the cells.
And within that code I did the following:
dummy = dummy & " # " & z_trim(ctrl.Caption) & vbCrLf
ActiveCell.Value = dummy
The issue is because of vbCrLf
If I write the strings into the cells the following way, the changes within my coloring run are fixed, there is no change by entering the cell in edit mode:
dummy = dummy & " # " & z_trim(ctrl.Caption) & Chr(10)
ActiveCell.Value = dummy
Picture of fixed issue
It works, so I'm fine. But still interessted, why vbCrLf is causing such confusing thing?

Line continuation not working in VBA for 2D Array construction

In the following Subroutine, defining a two dimensional array doesn't seem to work with line continuation. TestArray1 initializes as expected, but when I add line continuation I get the message,
"Compile Error - Closing bracket missing".
(Actually I'm not sure of the exact wording in English, doing this in German. In German the error message is,
"Fehler beim Komilieren: Fehlende schliesende Klammer".
I'm sure the English is not far off.)
Why would this not work?
Sub TestArrays()
Dim TestArray1 As Variant, TestArray2 As Variant
TestArray1 = [{"1String1", "1String2", "1String3"; "2String1", "2String2", "2String3"; "3String1", "3String2", "3String3"}]
TestArray2 = [{"1String1", "1String2", "1String3"; _
"2String1", "2String2", "2String3"; _
"3String1", "3String2", "3String3"]}
End Sub
Don't use square brackets.
Square brackets in VBA DO NOT stand for "this is an array", even though it looks like it (if you're any familiar with JSON anyway), and even though it might work.
Square brackets in VBA stand for "this is an expression that the host application will be evaluating at run-time".
In other words, it's giving work to Excel's expression evaluation engine: it's not VBA, it's Excel. The syntax of whatever is inside a square-bracketed expression must be legal in Excel's formula bar1.
Use the Array standard VBA function to create an array in VBA:
TestArray1 = Array("1String1", "1String2", "1String3", "2String1", "2String2", "2String3", "3String1", "3String2", "3String3")
Split it up with a line continuation at any point between two strings:
TestArray1 = Array( _
"1String1", "1String2", _
"1String3", "2String1", _
"2String2", "2String3", _
"3String1", "3String2", _
"3String3")
Note that the inconsistent ; vs , separators are probably part of the problem: Excel formulas use your system's list separator character: that's the character you'll want to use in square-bracket expressions - but you don't need to do that, because you don't need any square-bracket expressions.
There is no syntax for inline-initializing a 2D array in VBA. Declare & size your array explicitly instead:
Dim my2D(1 To 10, 1 To 10)
my2D(1, 1) = "1string1"
'...
If you have that much hard-coded strings in your code, then you are coding data. Data belongs in storage, not in code. Read the data from a worksheet, you'll get a 2D variant array for free, with a one-liner, without abusing language syntax, and if the data needs to change, then the code doesn't:
Dim my2D As Variant
my2D = sourceRange.Value
1 unless it's a VBA foreign identifier, in which case Excel doesn't get to evaluate it. Just don't use square bracket expressions, they're confusing.

Enter special characters in Excel VBA

How do I enter special characters in Excel VBA? For example if I want "●" (large interpunct) in some strings, they all appear as "?". I tried to substitute all "●" with ● in VBA but it didn't work, simply displayed ● in the string.
Reference Website - Unicode and VBA’s ChrW() and AscW() functions
Here the code for bullet et strong bullet. Use hexadecimal in lieu of long.
Sub DisplayBullet()
Cells(1, 1).Value = "This is a bullet - " & ChrW(8226)
Cells(2, 1).Value = "This is a strong bullet - " & ChrW(&H25CF)
End Sub
Important: If you try to display in a MsgBox it's not working.

Separate words with commas in Excel 2010

I'm trying to use a formula in Excel to separate a bunch of words in a cell with a comma. If there are more than 5 words in the cell, I just want to get the first 5 words. To get the first five words in a cell and separate them by a comma I use this:
=SUBSTITUTE(LEFT(A1,FIND("^",SUBSTITUTE(A1," ","^",5))-1), " ", ", ")
This works fine. But the problem with this, because of the number 5 here, if I a cell contains less than 5 words, I get an error. I tried to substitute the 5 with this:
LEN(TRIM(A1))-LEN(SUBSTITUTE(A1," ",""))+1
So my function becomes this:
=SUBSTITUTE(LEFT(A1,FIND("^",SUBSTITUTE(A1," ","^",LEN(TRIM(A1))-LEN(SUBSTITUTE(A1," ",""))+1))-1), " ", ", ")
But this doesn't work, it gives me an error. Any idea how I can do this please?
Also I would like to ignore the first word if its first character is "-" (without the quotes) and just start from the second word. So in other words, I want something like this:
I love my life very much should return I, love, my, life, very
- I love my life very much should return I, love, my, life, very (the "-" is ignored")
I love my should return I, love, my
Thanks in advance for any help
Here's a somewhat different approach. Aside from the "less than 5" issue, it also deals with the "5 words with no space at the end" issue:
=LEFT(A1,FIND("^",SUBSTITUTE(A1 & "^"," ","^",5))-1)
EDIT 1: I just noticed the part about the leading "- ". My addition isn't very elegant, but it deals with it, and also TRIMS any trailing spaces:
=TRIM(LEFT(IF(LEFT(A1,2)="- ",MID(A1,3,999),A1),FIND("^",SUBSTITUTE(IF(LEFT(A1,2)="- ",MID(A1,3,999),A1) & "^"," ","^",5))-1))
EDIT 2: Oh yeah, commas:
=SUBSTITUTE(TRIM(LEFT(IF(LEFT(A1,2)="- ",MID(A1,3,999),A1),FIND("^",SUBSTITUTE(IF(LEFT(A1,2)="- ",MID(A1,3,999),A1) & "^"," ","^",5))-1))," ",",")
Try this:
=TRIM(LEFT(SUBSTITUTE(SUBSTITUTE(TRIM(SUBSTITUTE(A1,"-"," "))," ",","),",",REPT(" ",99),5),99))
This will work even if there is not a space after the dash or if there are extra spaces in the text. Often I find that input is not very clean.
=SUBSTITUTE(LEFT(SUBSTITUTE(TRIM(SUBSTITUTE(A1,"-","",1)),
" ","*",5),IFERROR(FIND("*",SUBSTITUTE(TRIM(SUBSTITUTE(A1,"-","",1)),
" ","*",5))-1,999))," ",",")
Edit: After commenting on István's, I made mine flawless too.
=SUBSTITUTE(LEFT(SUBSTITUTE(TRIM(SUBSTITUTE(LEFT(TRIM(A1),1),"-"," ",1)
&MID(TRIM(A1),2,999))," ","*",5),IFERROR(FIND("*",SUBSTITUTE(
TRIM(SUBSTITUTE(LEFT(TRIM(A1),1),"-","",1)&MID(TRIM(A1),2,999))," ","*",5))-1,999))," ",",")
But I think his is more elegant.
Try this:
=SUBSTITUTE(LEFT(SUBSTITUTE(SUBSTITUTE(TRIM(SUBSTITUTE(A1,"- ","",1))&" "," ",", "),", ","|",MIN(LEN(SUBSTITUTE(TRIM(SUBSTITUTE(A1,"- ","",1))&" "," ",", "))-LEN(SUBSTITUTE(SUBSTITUTE(TRIM(SUBSTITUTE(A1,"- ","",1))&" "," ",", ")," ","")),5)),FIND("|",SUBSTITUTE(SUBSTITUTE(TRIM(SUBSTITUTE(A1,"- ","",1))&" "," ",", "),", ","|",MIN(LEN(SUBSTITUTE(TRIM(SUBSTITUTE(A1,"- ","",1))&" "," ",", "))-LEN(SUBSTITUTE(SUBSTITUTE(TRIM(SUBSTITUTE(A1,"- ","",1))&" "," ",", ")," ","")),5)))-1),",,",",")
The formula works by taking the following steps:
Remove any leading dash-space
Trim any leading or trailing spaces
Insert comma-spaces in place of spaces and add a trailing comma-space
Calculate the lesser of 5 and the number of words in the string
Put in "|" in place of either the fifth comma-space or the trailing comma-space if the string is less than five words
Determine the position of the "|"
Strip off the "|" and all characters to the right of it
Remove any doubled commas due to any single embedded commas in the initial string
If you are willing to consider a VBA solution, this complex expression can be replaced by a user-defined function:
Function words5(InputString As String) As String
Dim wordArray As Variant
wordArray = Split(Trim(Replace(InputString, _ 'remove "-", put words into array
"-", "", , 1)), " ")
ReDim Preserve wordArray(LBound(wordArray) To _ 'drop all but the first 5 words
WorksheetFunction.Min(UBound(wordArray), 5 - 1))
words5 = Replace(Join(wordArray, ", "), ",,", ",") 'rejoin the words with ", "
End Function 'separator
On the plus side of using this code is its maintainability compared to the worksheet formula, which impossible to understand or safely alter without access to the original building blocks that were combined into the single expression.
The code would have to be installed in the workbook in which it is used or in either the standard Personal.xlsb workbook or an addin workbook.
To use the function, copy and paste it into a standard module, which can be inserted into a workbook via the VBA editor. You can open the editor with the Visual Basic button on the `Developer tab of the ribbon.
Figured I'd throw my hat in the ring also. I think this formula should cover the bases:
=SUBSTITUTE(TRIM(LEFT(SUBSTITUTE(TRIM(SUBSTITUTE(A1&" ","- ",""))," ",REPT(" ",99)),99*5))," ",",")

Resources