Quotes and other special characters within string in VBA - excel

I am trying to write a long string in VBA with many special characters and I am stuck! On the shorter string, the double quotes worked well but on my final string, it doesn't work. I do not understand what's wrong.
"let Source = Csv.Document(File.Contents(""C:\Users\username\company\company Market Research - Documents\System\Data Project\raw data\mapped_tradeflows.csv""),[Delimiter="";"", Columns=7, Encoding=1252, QuoteStyle=QuoteStyle.None]), #""En-têtes promus"" = Table.PromoteHeaders(Source, [PromoteAllScalars=true]), #""Type modifié"" = Table.TransformColumnTypes(#""En-têtes promus"",{{""origin"", type text}, {""destination"", type text}, {""year"", Int64.Type}, {""month"", Int64.Type}, {""quality"", type text}, {""freight"", type text}, {""tonnage"", Double.Type}}) in #""Type modifié"""

Double quotations can be hard to read as you've demonstrated. Instead use Chr(34) to escape them.
For example
In this string is "another string"
Instead of
mystring = "In this string is ""another string"""
Use
mystring = "In this string is " & Chr(34) & "another string" & Chr(34)

Related

How can i get all the sub-children?

source link
Hello guys, so i have a function ("flecheD"),
(ColChild,ColParent,ParentActuel,source)=>
let
mylist=Table.Column(Table.SelectRows(source,each Record.Field(_,ColParent)=ParentActuel),ColChild),
resultat=Text.Combine(mylist)
in
Text.Trim(
if resultat ="" then "" else # resultat &"|" & # flecheD(ColChild,ColParent,resultat,source),"|")
which loops through 2 columns (Parent,Child) to get all children of the main parent (output->Children column). The problem is that when the function is confronted with several children, the resultat variable no longer has a single letter/child but several, which blocks the function from looking for the other sub-children.
In order to solve this, I tried to create a custom function "SubChilldren" with List.Generate()
(children as text, ColChild,ColParent,source)=>
let
i = 1,
length = Text.Length(children),
subchildren = List.Generate( ()=>#flecheD(ColChild,ColParent,Text.At(children,i-1),source), i<=length, i+1 )
in
Text.Combine(subchildren)
which when coupled with my initial function
(ColChild,ColParent,ParentActuel,source)=>
let
mylist=Table.Column(Table.SelectRows(source,each Record.Field(_,ColParent)=ParentActuel),ColChild),
resultat=Text.Combine(mylist)
in
Text.Trim(
if resultat ="" then "" else if Text.Length(resultat) = 1 then # resultat &"|" & # flecheD(ColChild,ColParent,resultat,source)
else #resultat &"|"& SubChildren(resultat,ColChild,ColParent,source),"|")
should normally get the sub-children of each children. However, it doesnt work . Could you please help me . Thx
I thought this was a fun way, but you could write a recursive function as well. I have it hard coded to 4 levels of children deep
(not sure how in your source data D child can have two parents, c and J, but whatever)
let Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Grouped Rows" = Table.Group(Source, {"Parent"}, {{"data", each List.RemoveNulls(_[Child]), type list}}),
Parent_List = List.Buffer(#"Grouped Rows"[Parent] ),
Child_List = List.Buffer(#"Grouped Rows"[data] ),
Process = (n as list) as list =>
let children = List.Transform(List.Transform(n, each Text.ToList(_)), each Text.Combine( List.Distinct(List.Combine(List.Transform(_, each try Child_List{List.PositionOf( Parent_List, _ )} otherwise null))))) in children,
Level1=Process(Source[Parent]),
Level2=Process(Level1),
Level3=Process(Level2),
Level4=Process(Level3),
Final=List.Transform(List.Positions(Level1),each Level1{_}&"|"&Level2{_}&"|"&Level3{_}&"|"&Level4{_}&"|"),
#"Replaced Value" = Table.ReplaceValue(Table.FromList(Final),"||","",Replacer.ReplaceText,{"Column1"}),
custom1 = Table.ToColumns(Source) & Table.ToColumns(#"Replaced Value"),
custom2 = Table.FromColumns(custom1,Table.ColumnNames(Source) & {"Children"})
in custom2
edited to be generic so it can take text as well as numerical inputs
let Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Parent", type text}, {"Child", type text}}),
#"Grouped Rows" = Table.Group(#"Changed Type", {"Parent"}, {{"data", each List.Transform(List.RemoveNulls(_[Child]), each Text.From(_)), type list}}),
Parent_List = List.Buffer(List.Transform(#"Grouped Rows"[Parent], each Text.From(_))),
Child_List = List.Buffer(#"Grouped Rows"[data]),
Process = (n as list) as list =>let children = List.Transform(List.Transform(n, each Text.Split(_,",") ) , each try Text.Combine(List.Distinct(List.Combine(List.Transform(_, each try Child_List{List.PositionOf( Parent_List, _ )} otherwise ""))),"," ) otherwise "") in children,
Level1=Process(#"Changed Type"[Parent]),
Level2=Process(Level1),
Level3=Process(Level2),
Level4=Process(Level3),
Final=List.Transform(List.Positions(Level1),each Level1{_}&"|"&Level2{_}&"|"&Level3{_}&"|"&Level4{_}&"|"),
#"Replaced Value" = Table.ReplaceValue(Table.FromColumns({Final}),"||","",Replacer.ReplaceText,{"Column1"}),
custom1 = Table.ToColumns(#"Changed Type") & Table.ToColumns(#"Replaced Value"),
custom2 = Table.FromColumns(custom1,Table.ColumnNames(#"Changed Type") & {"Children"})
in custom2

Replace by regular expresion in Excel

I have a list in Excel like the following:
1 / 6 / 45
123
1546
123 456
1247 /% 456 /
I want to create a new column with all sequences of consecutive non digits replaced by a character. In Google Sheets, this is easy using =REGEXREPLACE(A1&"/","\D+",","), resulting in:
1,6,45,
123,
1546,
123,456
1247,456,
In that formula A1&"/" is needed in order for REGEXREPLACE to work with numbers. No big deal, just adds a comma at the end.
How can we do this in Excel? Pure Power Query (not R, not Python, just M) is very much encouraged. VBA and other clickable Excel features are unacceptable (like find and replace).
If you have Excel 365:
In B1:
=LET(X,MID(A1,SEQUENCE(LEN(A1)),1),SUBSTITUTE(TRIM(CONCAT(IF(ISNUMBER(--X),X," ")))," ",","))
Or if streaks of digits are always delimited by at least a space:
=TEXTJOIN(",",,FILTERXML("<t><s>"&SUBSTITUTE(A1," ","</s><s>")&"</s></t>","//s[.*0=0]"))
Another option, if you have got access to it, is LAMBDA(). Make a function to replace all kind of characters, something along the lines of this. Without LAMBDA() and TEXTJOIN() I think your best bet would be to start nesting SUBSTITUTE() functions.
Here is a Power Query solution.
It makes use of the List.Accumulate function to determine whether to add a digit, or a comma, to the string:
Note that the code replicates what you show for results. If you prefer to avoid trailing (and/or leading) commas, it can be easily modified.
let
Source = Excel.CurrentWorkbook(){[Name="Table5"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Column1", type text}}),
#"Added Custom" = Table.AddColumn(#"Changed Type", "textToList", each List.Combine({Text.ToList([Column1]),{","}})),
#"Added Custom1" = Table.AddColumn(#"Added Custom", "commaTerminators", each List.Accumulate(
[textToList],"", (state,current) =>
if List.Contains({"0".."9"},current)
then state & current
else if Text.EndsWith(state,",")
then state
else state & ",")),
#"Removed Columns" = Table.RemoveColumns(#"Added Custom1",{"textToList"})
in
#"Removed Columns"
Edit To eliminate leading/trailing commas, we add the Text.Trim function which, in Power Query, allows defining a specific text to Trim from the start/end:
let
Source = Excel.CurrentWorkbook(){[Name="Table5"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Column1", type text}}),
#"Added Custom" = Table.AddColumn(#"Changed Type", "textToList", each List.Combine({Text.ToList([Column1]),{","}})),
#"Added Custom1" = Table.AddColumn(#"Added Custom", "commaTerminators", each
Text.Trim(
List.Accumulate(
[textToList],"", (state,current) =>
if List.Contains({"0".."9"},current)
then state & current
else if Text.EndsWith(state,",")
then state
else state & ","),
",")),
#"Removed Columns" = Table.RemoveColumns(#"Added Custom1",{"textToList"})
in
#"Removed Columns"
VBA UDF You mentioned you did not want VBA, but not clear if you were restricting that to a "clickable". Here is a user defined function that you can use on a worksheet directly. It uses the VBA regex engine which allows easy extraction of multiple matches
You can enter a formula on the worksheet such as =commaSep(cell_ref) to get the same results as shown above in my second PQ example
Option Explicit
Function commaSep(S As String) As String
Dim RE As Object, MC As Object, M As Object
Dim sTemp As String
Set RE = CreateObject("vbscript.regexp")
With RE
.Global = True
.Pattern = "\d+"
If .test(S) Then
Set MC = .Execute(S)
sTemp = ""
For Each M In MC
sTemp = sTemp & "," & M
Next M
commaSep = Mid(sTemp, 2)
Else
commaSep = "no digits"
End If
End With
This is another variation if you have TEXTJOIN function available.
=SUBSTITUTE(TRIM(TEXTJOIN("",TRUE,IFERROR(MID(A2,ROW($A$1:INDEX(A:A,LEN(A2))),1)+0," ")))," ",",")
And another option in Power Query.
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WMlTQVzADYhNTpVgdINfIGEKbmpjBBIByZgpQjom5gr4qWEBfKTYWAA==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Column1 = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Column1", type text}}),
x1 = Table.AddColumn(#"Changed Type", "x1", each Text.ToList([Column1])),
x2 = Table.AddColumn(x1, "x2", each List.Transform([x1], each if Text.Contains("0123456789", _) then _ else " " )),
x3 = Table.AddColumn(x2, "x3", each Text.Split(Text.Combine([x2])," ")),
x4 = Table.AddColumn(x3, "x4", each List.Transform([x3], each if Text.Contains("0123456789", try Text.At(_,0) otherwise " ") then _&"," else "" )),
x5 = Table.AddColumn(x4, "x5", each Text.Combine([x4])),
#"Removed Columns" = Table.RemoveColumns(x5,{"x1", "x2", "x3", "x4"})
in
#"Removed Columns"

Merging Columns - Run-time Error 1004: Power Query Macro

Hoping you can help solve a problem that has melted my brains for the past number of days.
I'm new to marcos and Excel Power Query in particular, I am trying to merge a number of non adjoining columns in a workbook and was able to do this successfully in Power Query. My aim is to automate this as much as possible so I decided to record a macro.
When running the recorded macro however I am getting Run-time Error 1004.
My Macro code is as follows:
Sub PQ_CSATMerge()
'
' PQ_CSATMerge Macro
'
'
Columns("A:A").Select
Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
Selection.CurrentRegion.Select
Application.CutCopyMode = False
ActiveSheet.ListObjects.Add(xlSrcRange, Range("$A$1:$CS$816"), ,
xlYes).Name = _
"Table3"
Range("Table3[#All]").Select
ActiveWorkbook.Queries.Add Name:="Table3", Formula:= _
"let" & Chr(13) & "" & Chr(10) & " Source = Excel.CurrentWorkbook(){[Name=""Table3""]}[Content]," & Chr(13) & "" & Chr(10) & " #""Changed Type"" = Table.TransformColumnTypes(Source,{{""Column1"", type any}, {""Start (UTC)"", type datetime}, {""Visitor ID"", type text}, {""Visitor Name"", type text}, {""MCS"", Int64.Type}, {""Skill"", type text}, {""Agent Name"", type text}, {""Agent Login Name"", type text}, {""Agen" & _
"t Full Name"", type text}, {""Agent Group"", type text}, {""Chat Start Reason"", type text}, {""Chat End Reason"", type text}, {""Chat Requested Time (UTC)"", type datetime}, {""Length (seconds)"", Int64.Type}, {""Interactive"", type logical}, {""Engagement ID"", Int64.Type}, {""Goal"", type text}, {""Campaign"", type text}, {""Target Audience"", type text}, {""Enga" & _
"gement Name"", type text}, {""Visitor Behavior"", type text}, {""Country"", type text}, {""State"", type text}, {""City"", type text}, {""ISP"", type text}, {""Organization"", type text}, {""IP Address"", type text}, {""Device"", type text}, {""Browser"", type text}, {""Operating System"", type text}, {""Chat Start Page"", type text}, {""Chat Start URL"", type text}" & _
", {""Transcript"", type text}, {""Personal Info Exists"", type logical}, {""Customer Info Exists"", type logical}, {""Marketing Source Exists"", type logical}, {""Lead Exists"", type logical}, {""Lead - Topic"", type text}, {""Visitor Error Exists"", type logical}, {""Service Activity Exists"", type logical}, {""Viewed Product Exists"", type logical}, {""Viewed Prod" & _
"uct - Products"", type any}, {""Transaction Exists"", type logical}, {""Transaction - Total"", type any}, {""Transaction - Order ID"", type any}, {""Cart Update Exists"", type logical}, {""Cart Update - Total"", Int64.Type}, {""Cart Update - Number of Items"", Int64.Type}, {""Cart Update - Products"", type any}, {""Pre-Chat Survey Exists"", type logical}, {""Post-Ch" & _
"at Survey Exists"", type logical}, {""Agent Survey Exists"", type logical}, {""Chat Data Enriched"", type logical}, {""Line of Business"", type text}, {""Search Content Exists"", type logical}, {""CoBrowse - Num Sessions"", Int64.Type}, {""CoBrowse - Num Interactive Sessions"", Int64.Type}, {""Alerted MCS"", Int64.Type}, {""Chat MCS"", Int64.Type}, {""Exit Survey - " & _
"France - Exit Survey - Voulez-vous recevoir une transcription de ce chat?"", type text}, {""Exit Survey - France - Exit Survey - Adresse e-mail"", type text}, {""Exit Survey - France - Exit Survey - L'agent du chat était-il capable de résoudre votre requête ou de vous diriger vers une personne capable de vous aider ?"", type text}, {""Exit Survey - France - Exit Sur" & _
"vey - Quelle est la probabilité de recommander SAS à un ami ou à un collègue?"", type any}, {""French_CSAT"", type text}, {""Exit Survey - France - Exit Survey - Dans l'ensemble, était-il facile d'obtenir l'information ou l'aide dont vous avez eu besoin aujourd'hui?"", type text}, {""Exit Survey - France - Exit Survey - Veuillez nous faire part de vos commentaires o" & _
"u suggestions sur la meilleure façon de vous servir"", type text}, {""Exit Survey - Italy - Exit Survey - Desidera ricevere per email una copia della chat?"", type text}, {""Exit Survey - Italy - Exit Survey - Se sì, la preghiamo di fornire la sua email:"", type text}, {""Exit Survey - Italy - Exit Survey - Raccomanderebbe SAS ad un amico o un collega?"", type any}," & _
" {""Italian_CSAT"", type text}, {""Exit Survey - Italy - Exit Survey - Nel complesso, quanto è stato facile ottenere le informazioni o l’aiuto di cui aveva bisogno oggi?"", type text}, {""Exit Survey - Italy - Exit Survey - La preghiamo di fornire dei suggerimenti al fine di poter migliorare il nostro servizio:"", type text}, {""Exit Survey - Netherlands - Exit Surv" & _
"ey - Wilt u dat wij u een kopie van deze chat emailen?"", type text}, {""Exit Survey - Netherlands - Exit Survey - Email adres"", type text}, {""Exit Survey - Netherlands - Exit Survey - Was de chatagent in staat om uw vraag op te lossen of u te leiden naar iemand die kan helpen?"", type text}, {""Exit Survey - Netherlands - Exit Survey - Hoe waarschijnlijk zou u SA" & _
"S aan een vriend of collega aanbevelen?"", Int64.Type}, {""Dutch_CSAT"", type text}, {""Exit Survey - Netherlands - Exit Survey - Hoe makkelijk was het om de informatie of hulp die u nodig had vandaag te verkrijgen?"", type text}, {""Exit Survey - Netherlands - Exit Survey - Geef ons alstublieft feedback of suggesties over hoe we u beter kunnen bedienen. "", type te" & _
"xt}, {""Exit Survey - SAS Exit Survey - English - Would you like us to email you a transcript of this chat?"", type text}, {""Exit Survey - SAS Exit Survey - English - Email Address"", type text}, {""Exit Survey - SAS Exit Survey - English - Was the chat representative able to resolve your inquiry or direct you to someone#(cr)#(lf)who could help?"", type text}, {""E" & _
"nglish_CSAT"", type text}, {""Exit Survey - SAS Exit Survey - English - How likely would you be to recommend SAS to a friend or colleague?"", type any}, {""Exit Survey - SAS Exit Survey - English - Overall, how easy was it to get the information or help you needed today?"", type any}, {""Exit Survey - SAS Exit Survey - English - Please provide us with any feedback o" & _
"r suggestions for how we can serve you better."", type text}, {""Exit Survey - Spain - Exit Survey - ¿Le gustaría que le enviemos por correo email una copia de este chat?"", type text}, {""Exit Survey - Spain - Exit Survey - Email"", type text}, {""Exit Survey - Spain - Exit Survey - El agente del chat fue capaz de resolver tu consulta o dirigirte a alguien que podr" & _
"ía ayudarte?"", type text}, {""Exit Survey - Spain - Exit Survey - ¿Qué probabilidad hay que le recomiende SAS a un amigo o compañero?"", type text}, {""Spanish_CSAT"", type text}, {""Exit Survey - Spain - Exit Survey - En general, con que facilidad ha recibido la información o ayuda que necesitaba hoy?"", type text}, {""Exit Survey - Spain - Exit Survey - Por favor" & _
", facilítanos cualquier comentario o sugerencia sobre cómo podemos mejorar el servicio."", type any}, {""Chat Operator Survey - SAS Operator Survey - English - What was the nature of the chat?"", type text}, {""Chat Operator Survey - SAS Operator Survey - English - Referred or Resolved?"", type text}, {""Chat Operator Survey - SAS Operator Survey - English - Area""," & _
" type text}, {""Chat Operator Survey - SAS Operator Survey - English - If further explanation needed, please provide here:"", type text}})," & Chr(13) & "" & Chr(10) & " #""Merged Columns"" = Table.CombineColumns(Table.TransformColumnTypes(#""Changed Type"", {{""Column1"", type text}}, ""en-GB""),{""Column1"", ""French_CSAT"", ""Italian_CSAT"", ""Dutch_CSAT"", ""English_CSAT"", ""Spanish_CS" & _
"AT""},Combiner.CombineTextByDelimiter("""", QuoteStyle.None),""Merged CSAT"")" & Chr(13) & "" & Chr(10) & "in" & Chr(13) & "" & Chr(10) & " #""Merged Columns"""
ActiveWorkbook.Worksheets.Add
With ActiveSheet.ListObjects.Add(SourceType:=0, Source:= _
"OLEDB;Provider=Microsoft.Mashup.OleDb.1;Data Source=$Workbook$;Location=Table3;Extended Properties=""""" _
, Destination:=Range("$A$1")).QueryTable
.CommandType = xlCmdSql
.CommandText = Array("SELECT * FROM [Table3]")
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.BackgroundQuery = True
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.PreserveColumnInfo = True
.ListObject.DisplayName = "Table3_2"
.Refresh BackgroundQuery:=False
End With
End Sub

Power query Error.Record

How do I spit out records, to show up in the workbook queries pane as error records pls?
For example, if the [AcctClass] <> [_checkAcctClass] columns do not match, reject that record as an error
let
source = AccountIDsWithDuplicates,
grouped = Table.Group(source, {"AcctID"}, {{"AcctClass", each List.Max([AcctClass]), type logical}, {"_checkAcctClass", each List.Min([AcctClass]), type logical}, {"Sum_Bal", each List.Sum([#"Bal_EUR"]), type number}}),
// Make sure accounts only have one AcctClass
ErrorRecords = Table.SelectRows(grouped, each([AcctClass] <> [_checkAcctClass])
in
grouped
Composing Table.TransformRows to create errors and then putting them back in a table with Table.FromRecords might do what you want?
= Table.FromRecords(Table.TransformRows(grouped, each if [AcctClass] <> [_checkAcctClass] then error "didn't match" else _), Value.Type(grouped))
If the first row is an error then Table.FromRecords will completely break, but you can work around that by telling it what table type to expect.
Example mashup:
let
Source = Csv.Document("AcctID,AcctClass
1,false
1,true
2,true
2,true"),
#"Promoted Headers" = Table.PromoteHeaders(Source),
AccountIDsWithDuplicates = Table.TransformColumnTypes(#"Promoted Headers",{{"AcctID", Int64.Type}, {"AcctClass", type logical}}),
grouped = Table.Group(AccountIDsWithDuplicates, {"AcctID"}, {{"AcctClass", each List.Max([AcctClass]), type logical}, {"_checkAcctClass", each List.Min([AcctClass]), type logical}}),
ErrorRecords = Table.FromRecords(Table.TransformRows(grouped, each if [AcctClass] <> [_checkAcctClass] then error "didn't match" else _), Value.Type(grouped))
in
ErrorRecords

Help with function in string

I have a variable, emailBody, which is set to a string stored in a database. The email body is set to a string via a dlookup function.
emailBody = DLookup("emailBody", "listAdditions", "Id = " & itemType)
The string that email body is set to includes an IIf function (which includes a dlookup function). When
?emailBody is entered in the immediate window during runtime, it shows that emailBody is set to the following string:
The new commodity is" & Iif(dlookup("IsVague", "CommodityType", "Description= " & newItem)="1", "vague.", "not vague.")
However, I want the dlookup and IIf functions to be evaluated and their results stored in the string. How do I properly format the emailBody string ("the new commodity...") in my database so that the functions will be evaluated and the results stored in the emailBody variable?
Your question is a bit unclear, but if [Id] (Or [Description]) is a string, then you Dlookup must be like this:
emailBody = DLookup("emailBody", "listAdditions", "Id = '" & itemType & "'")
or
emailBody = DLookup("emailBody", "listAdditions", "Id = """ & itemType & """")
That is, your constant should be surrounded by quotes. You can either use ' (single quote) or "" (doubled double quote).
I am somewhat concerned about the value of newitem, but in general you can use Eval:
s = """The new commodity is"" & " _
& "Iif(dlookup(""IsVague"", ""CommodityType"", ""Description= "" & newItem)=""1"", ""vague."", ""not vague."")"
s2 = Eval(s)
I am not sure that this is the way to go, think about it.
So you have this exact string stored in a table field, and you want Access/VBA to evaluate it, correct?
"The new commodity is " & Iif(dlookup("IsVague", "CommodityType", "Description= " & newItem)="1", "vague.", "not vague.")
If so, try the Eval() command:
emailBody = Eval(DLookup("emailBody", "listAdditions", "Id = " & itemType))

Resources