In Excel VBA, how do I refer to a named column that contains a single quote - vba

I am investigating a bug in an Excel spreadsheet where the following formula is inserted into every cell in a column.
=AGGREGATE( 3, 5, InputData[#[Foo]:[Bar]]) > 0
The VBA is as follows:
Let AddColumn.DataBodyRange.formula = "=AGGREGATE( 3, 5, [#[Foo]:[Bar]]) > 0"
this will evaluate to FALSE if all of the cells on the current row between columns Foo and Bar are empty, otherwise it evaluates to TRUE
The problem I'm seeing is that the names Foo and Bar are variable and not under my control and the formula fails with Run-time error 1004 if a name contains a single quote:
Let AddColumn.DataBodyRange.formula = "=AGGREGATE( 3, 5, [#[Foo's name]:[Bar]]) > 0"
Is there a way I can escape the name in such a way that single quotes won't create the run-time error? Adding double quotes around the name gives me the same error.
Are there likely to be further problems if the names contain other characters that have special meaning in Excel?
I could also refer to the columns by address instead of name. Would that work with the current row '#' notation?
Excel version:14.0.7188.5002

I hear you when you say the naming convention is "not under my control". This really puts you in a bind when anything can be pumped into your code.
Sadly, the only solution is to scrub the input when they finally hand it over to you. This involves you having to make your own vba function that takes in a string and returns a string that has special characters removed (or replaced with something else).
In your case, you are going to have to scrub the data in possibly two places.
First, you will need to change all the column names so they don't have special characters in them. You'll need to access each name and send it through the 'scrub' function and then replace the name with the scrubbed name.
Second, when someone inputs a column name for your AGGREGATE, you'll need to capture that input into a string variable and then pass that through the 'scrub' function. Then you'll need to validate that the input they gave you matches up with a valid column name. If it's not valid, send them an error message asking them to enter a valid name or to cancel out.
After you have valid values for foo and bar, you can add them to your AGGREGATE function and let it execute.
If you can't scrub/change your column names, then you'll have to make a list of scrubbed column names and associate them with the column address. Then when you get your input, scrub it, and then match to the list to grab the correct address. Then you can use hard addresses instead of variable naming schemes.
It's a lot of work. But it's necessary when you have naming conventions that are not under your control.

The other answers and comments put me on the right track:
Function escapedColumnName(columnName As String) As String
columnName = Replace(columnName, "'", "''")
columnName = Replace(columnName, "#", "'#")
columnName = Replace(columnName, "[", "'[")
columnName = Replace(columnName, "]", "']")
escapedColumnName = columnName
End Function

Related

DLookup returning True for some values, and False for others

I am writing a program, and I need to be able to check whether a certain 'tag' exists, by looking at all the 'tags' in the column 'CowTagMain' of the 'CowTable' table.
The code I am using is,
DLookup("[CowTagMain]", "[CowTable]", "[CowTagMain]") = Tag ...
Where tag is a String, TagMain is the column, and MainTable, is the table I am fetching data from.
I am getting inconsistent results, when I try this with 18C, it returns true. While if I try this with 18, it returns false.
I would assume I am fundamentally misunderstanding how to use DLookup, but after searching the internet for hours I cannot understand what I am doing wrong.
Even just pointing me in the right direction would be very appreciated! I am new to working with Access and VBA.
The search criteria is not within the function WHERE CONDITION argument.
The field is text type so need apostrophe delimiters.
Consider:
If IsNull(DLookup("[CowTagMain]", "[CowTable]", "[CowTagMain]= '" & Tag & "'")) Then

Google Script Sheets API - default number format

It looks like google sheets is making the same mistake as Excel, by "thinking ahead" and converting the value "1.1.1" to 2001.01.01 when doing sheet.appendRow. I have tried to set the number format of the column in charge to "#" (which should be plain text) before inserting rows - but looks ineffective. On the other hand doing the same after inserts is also ineffective, as the content is already "date".
Adding ' before is working, but it is not what I need.
Is there any way to give a default format or to disable such automatic conversion (from google script)?
I have a cell in which a form deposits a variable number of values seperated by a comma such as: " 1, 2, 4, 6 " etc - when there are only three answers, Google "helps" me by converting the value into a date object. But it's supposed to be a list of choices...
It's not pretty, but I've managed a workaround by using .getDisplayValue instead of .getValue - it does change the cell value into a string, so if you need to do further manipulations that are dependent on the value being a number or something, obviously, this fails.
I overwrite the value for the problem cell in my array before passing it to .appendRow
//getting the values
var values = s.getRange(row,1,1,lastCol).getValues()[0];
//brute force crushing of problem value
values[5] = s.getRange(row,6).getDisplayValue();

How to categorise a column in excel based on another column containing value in string with delimiter ; where string can have two separate words

This question is a follow up to a previous query: How to categorise a column in excel based on another column that contains value in string separated by semicolons
I have the following spreadsheet (please click on link below for image):
Raw data and expected output
My question is I want to categorise the raw data so the output is as pictured in B16:B34 and C16:C34. I am trying to categorise people by their interests when their interests are in a column containing strings separated by semicolon with multiple words. The Name can come up multiple times according to their interests where in this case Movie, Action Movie, Music, Rock Music, Jazz Music and Radio.
I have tried the answer provided by #Glitch_doctor:
{=IFERROR(INDEX($B$1:$B$11,SMALL(IF(ISNUMBER(SEARCH(B$15,$C$1:$C$11)),ROW($C$1:$C$11)-ROW(INDEX($C$1:$C$11,1,1))+1),ROW(1:1))),"")}
The issue with the answer is that when a person's interest is actually Action Movie they show up in the Movie categorisation. I am trying to match when their interest is Action Movie they only show up in Action Movie after categorisation. Multiple words doesn't seem to work with SEARCH function.
I tried to replace the SEARCH function with a VBA code:
Function ProjectSearch(ByVal strProj As String, ByVal strVal As String, _
Optional ByVal delimiter As String = ";") As Boolean
Dim i As Long
Dim strSplit() As String
strSplit = Split(strProj, delimiter)
ProjectSearch = False
For i = LBound(strSplit) To UBound(strSplit)
If strSplit(i) = strVal Then
ProjectSearch = True
Exit Function
End If
Next i
End Function
Since I am a newbie it doesn't seem to work. My question is there a way where I can do what I want without VBA? If I do need to use VBA what do I need to do?
Thanks kindly in advance.
Okay, that was much simpler than I was expecting it to be:
=IFERROR(INDEX($C$1:$C$11,SMALL(IF(ISNUMBER(IF(SEARCH(E$15,$D$1:$D$11)=1,SEARCH(E$15,$D$1:$D$11),SEARCH(CONCATENATE("; ",E$15),$D$1:$D$11))),ROW($D$1:$D$11)-ROW(INDEX($D$1:$D$11,1,1))+1),ROW(1:1))),"")
I only changed the ISNUMBER(SEARCH(B$15,$C$1:$C$11)) part to ISNUMBER(IF(SEARCH(E$15,$D$1:$D$11)=1,SEARCH(E$15,$D$1:$D$11),SEARCH(CONCATENATE("; ",E$15),$D$1:$D$11)))
The addition IF statement is saying that if the search finds the single word as the first character in the cell to accept that search into the array, otherwise search beginning with "; " instead.

Word Macro for separating a comma-separated list to columns

I have a very large set of data that represents cartesian coordinates in the form x0,y0,z0,x1,y1,z1...xn,yn,zn. I need to create a new line at the end of each xyz coordinate. I have been trying to record a macro that moves a certain number of spaces from the beginning of each line, then creates a new line. This, of course, will not work since the number of digits in each xyz coordinate differs.
How can I create a macro to do this in Microsoft Word?
Try this:
Public Sub test()
Dim s As String
Dim v As Variant
Dim t As String
Dim I As Long
s = "x0,y0,z0,x1,y1,z1,xn,yn,zn"
v = Split(s, ",")
t = ""
For I = LBound(v) To UBound(v)
t = t + v(I)
If I Mod 3 = 2 Then
t = t + vbCr
Else
t = t + ","
End If
Next I
t = Left(t, Len(t) - 1)
Debug.Print t
End Sub
The Split function splits a string along the delimiter you specify (comma in your case), returning the results in a 0-based array. Then in the For loop we stitch the pieces back together, using a carriage return (vbCR) every third element and a comma otherwise.
The final (optional) step is to remove the trailing carriage return.
Hope that helps
The question placed before us was most clearly asked
“Please produce a macro sufficient to the task
I have Cartesian coordinates, a single line of these
Array them in many lines, triplets if you please!”
Instinctively we start to code, a solution for this quest
Often without asking, “Is this way truly best?”
But then another scheme arises from the mind
That most venerated duo: Word Replace and Find
Provide the two textboxes each an encantation
Check the Wildcard option and prepare for Amazation!
Forgive me!
In Word open Find/Replace
Click the More button and check the Use wildcards box
For Find what enter ([!,]{1,},[!,]{1,},[!,]{1,}),
For Replace with enter \1^p
Use Find Next, Replace and Replace All as usual
How it works
With wildcards, [!,]{1,} finds one or more chars that are NOT commas. This idiom is repeated 3 times with 2 commas separating the 3 instances. This will match 3 comma-delimited coordinates. The whole expression is then wrapped in parentheses to created an auto-numbered group (in this case Group #1). Creating a group allows us to save text that matches the pattern and use it in the Replace box. Outside of the parentheses is one more comma, which separates one triplet of coordinates from the next.
In the Replace box \1 retrieves auto-numbered group 1, which is our coordinate triplet. Following that is ^p which is a new paragraph in Word.
Hope that helps!

How to tell if carriage return is in my string?

I have a textbox control that allows for the user of enter button to enter details like ADdresses or other demographic information. Since the default for addresses are as follows:
Address 1
Address 2
City, st
Zip
I am wondering if there is a way to tell if the Enter key was used to make a new line here? I've looked around and currently the only is to have a check in VB for vbCrLf however I'm not seeing it pick this up in the code.
Test data for this would be something similar to below
123 N Street
S Test Street
Test City, XX
91883
The code below is what I'm trying to just replace any return carriage and replace with a space
Text.Replace(vbCrLf, " ")
Will this vbCrLf not pick up a carriage return unless there's an actual space between the above test values?
If you are using a MultiLine textbox (as it seems from your sample) then you don't need to search for the newline characters and replace them with a space.
You could simply use the Lines property where every line is stored separated from the other and then use the string Join method to create a single line string
Dim singleLine = string.Join(" ", myTextBox.Lines)
Of course if you are just interested to know if there is a newline character then just check the Length property of the Lines array
vbCrLf actually refers to two characters, a carriage return (13) and a line feed (10).
I would search and replace each separately. It isn't strictly necessary (as replace will work on the two characters at once), but can catch instances in which the user cut and pasted information, instead of typing directly into the text box.
Text = Text.Replace(vbCr, " ")
Text = Text.Replace(vbLf, " ")
or
Text = Text.Replace(vbCr, " ").Replace(vbLf, " ")
https://msdn.microsoft.com/en-us/library/microsoft.visualbasic.constants.vbcrlf(v=vs.110).aspx
The Replace() function will indeed properly detect and replace all occurrences of the target with the replacement - it does not matter whether there are leading or trailing spaces.
However, please consider that String objects are immutable and cannot be changed after they have been instantiated. Therefore, Replace() does not modify the existing object but rather returns a new string as its result.
To actually see the results of the function call, you need to do something along these lines:
newString = Text.Replace(vbCrLf, " ")
I spent quite some time to resolve exactly this problem, the solution I came across was:
text = text.Replace(" ", ControlChars.CrLf)
Sorry cant remember where I found the solution but if I do remember it I will post the link here.