Google App Script - Docs - Removing unused Items After Merging Content - RegEx? - javascript

I have a Google Form bound to a Sheet. My Script is in the sheet. Sometimes a set of fields in the Form will be blank / not filled in, this is intentional.
When this happens I want to remove these unused merging elements from the Doc before saving and closing it. There can be 7 to 20 unused elements that I want to remove when this happens.
I have tried so many things. I do not want to hard code it as there will be changes made/ other additions made moving forward. This would be an easy fix but not a correct solution.
I am thinking the RegEx after the merge is the way to go, but I'm open to any suggestions.
The Fields are formatted like this: {{NAME}} or {{OtherName}} or {{Some Name}} or {{Street Name}}, {{State Name}} as in an address. I am also trying to remove any extra spaces and am struggling as to how to remove the ",". Maybe I should be adding the "," when merging the field instead of it being a static part of the page.
Here is my RegEx. I'm new to it and tried following the GAS guide to build this:
body.replaceText(/([{]{2}|^)[\w.]\s{0,1}[\w.]{0,1}([}]{2}|$)/ , '');
//OR
body.replaceText(/(\W\W|^)[\w.]\s{0,1}[\w.]{0,1}(\W\W|$)/ , '');
//OR
var pattern = /([{]{2}|^)[\w.]\s{0,1}[\w.]{0,1}([}]{2}$)/;
body.replaceText(pattern , '');
I have spent hours on this issue trying Start and End, loops and any other solution I could think of or find to adapt to my need and am at my wits end.
Thanks

Related

Javascript - Update to pipe delimiter with array that contains commas

I've been looking through stack overflow and the internet in general for hours with no solution in site yet...
I'll explain what I'm attempting to do - I'm building a list, then using php explode command by comma so I can loop through it, and insert each record into the database.
However, I'm building the array javascript, and the values I'm building the array off of, contain commas, separating first name and last name (Format Ex: Firstname, Lastname).
I'm a beginner and I'm still learning, so any help to point in the right direction would be greatly appreciated. I'm wondering if I need to do math to count the commas on the php side in order to separate based off the comma count, or if this is achievable in javascript using regex..
Everything I've been looking at seems like I may have to learn some regex to resolve this... Perhaps there's a built in jQuery command to change delimiter that I haven't been able to find?
var labels = $('.list-left ul li.active').map(function(){
return $(this).text().split(',').join('|');
}).get();
Maybe like this:
var test='test1,test2,test3,test4';
var test_new=test.replace(new RegExp(',','g'), '|');
console.log(test_new);

Regex on multiple lines of random order

I am using BIRT to design a report based on a database, and one of the fields of the form contain multiple lines, like that :
Site: Place ThePlace
Room: D2 RMD3
InstanceId: OI-RandomChars
The fact is, they are not always in this order, as it is user input (in an other form, not BIRT prompt).
And please note that these fields contain capital letters.
So what I want to do is to extract in three separate columns, so with three regex in JavaScript the Site, the Room, and the InstanceId.
I have tried many things with like catching each row until the end of the line or playing around substrings with various conditions ... and so far I think the best to do is to use string function replace to remove anything different than what I want to catch.
An example for the row Room would be :
row["Log"].replace(/?![Room:\s\S*\s]/, "")
I get an error with this but you can see what I try to do.
Thanks for all the consideration about my problem.
A single regex can become overly complicated and hard to read and mantain for this kind of job.
I would probably consider doing it programmatically like your first instinct was.
First I would consider splitting the string into lines
var lines = string.split("\n\n");
This will split all your double lines into an array
["Site: Place ThePlace", "Room: D2 RMD3", "InstanceId: OI-RandomChars"]
Then cycle trough all your lines and then make your checks.
Your check now can actually be regex if you want, or using substring.
This is an example:
var site, room, InstanceId;
var siteCheckRegex = new Regex("^Site:");
for(var i=0; i<lines.length; i++){
if(siteCheckRegex.test(lines[i])){
site = lines[i].replace("Site:","");
}
[...]
}
It actually depends on what you really want to get out of it and the problem and difference you can find in the user input data.

xPath in selenium with multiple premises in multiple node layers

I am having a little problem with xpath in seleniumdriver.
I would like an xpath locator to narrow down its selection via two variables using exact matching at different points of the node hiearchy. This part is done.
You may imagine my case as addressing a two dimensional array in the xml with xPath, with each dimension being given as the two variables I have in it(they are standard text searches via js variables, not xpath variables).
What I'm struggling with is the resulting construction does not tell the difference between the elements of the first dimension, so as long as the given variable value is one of the dimensions, it will address every element in the second dimension fine. I can not assume they are unique or they are in any order. I am using it for testing so this is not acceptable.
How can I form an expression that will not doesn't do the same mistake?
I have tried the 'and' expression but both selenium and xpath tools say the value is '1' for 'found' but it doesn't give me a node locator to work with.
Example, my structure looks similar, so addressing it properly by x1/y1 for example looks fine.
//x1//y1
//x1//y2
//x2//y3
//x2//y4
//x3//y5
//x3//y6
Should work, works ok.
//x1x//y1
//x1x//y2
//x2x//y3
//x2x//y4
//x3x//y5
//x3x//y6
(Giving nonexistent input as 1st dimension.) My input is not fault tolerant, I look for exact value so the tests fail here as they should.
//x2//y1
//x2//y2
//x3//y3
//x3//y4
//x1//y5
//x1//y6
DING, the locator finds y values here when it should not(the y vales are on different leaves of the node tree). I need help with this.
Here is the locator in question:
return element(by.xpath(".//div[#name='typeList']//div[.//text()='" + moduleName + "']//div[./text()='" + typeName + "']")).getText();
TypeList is the name of the owner element, it does not make any differnece if I remove it, but please keep it in mind when giving me examples.
In the end, it was indeed a syntactical problem, before the text keywords.
I was trying this
//div[./text()='Zero']//div[./text()='Number']
Instead, I needed something like this.
//div[.//text()='Zero']/div[.//text()='Number']
Apparently the first one does looks for 'Number' regardless the value of the first constraint as long as every is defined in my file(does not have to be in its upward xnode path.)
As a final note, I advise against using the chrome xpath helper as its behavior is near random, it gives different results after deleting and replacing the same expression. Ugh. The only other one for chrome is adware... I figured my result out by trial and error with the firefox xpath checker tool.
1, I ended up needing to additionally add an node upwards for the element for angular select ui tool(we use selectize.js, a searchable select box), else it was confused what to return, but this is unrelated to the original question as I tried that before with the original expression.
2, I also had to add a node between the first and second text search, else it would look for the second expression in the first one too, eg. looking for Number in Zero, and treat it like a valid value if found. The problem still occurs the other way around, this can be fixed too by applying additional type/name constraints in the first one(not in final example to save space).
So this is what I ended up with:
.//div[#name='typeList']//div/div[.//text()='Zero']/div/div/div[.//text()='Number']

jQuery "Autocomplete" plugin is messing up the order of my data

I'm using Jorn Zaefferer's Autocomplete plugin on a couple of different pages. In both instances, the order of displayed strings is a little bit messed up.
Example 1: array of strings: basically they are in alphabetical order except for General Knowledge which has been pushed to the top:
General Knowledge,Art and Design,Business Studies,Citizenship,Design and Technology,English,Geography,History,ICT,Mathematics,MFL French,MFL German,MFL Spanish,Music,Physical Education,PSHE,Religious Education,Science,Something Else
Displayed strings:
General Knowledge,Geography,Art and Design,Business Studies,Citizenship,Design and Technology,English,History,ICT,Mathematics,MFL French,MFL German,MFL Spanish,Music,Physical Education,PSHE,Religious Education,Science,Something Else
Note that Geography has been pushed to be the second item, after General Knowledge. The rest are all fine.
Example 2: array of strings: as above but with Cross-curricular instead of General Knowledge.
Cross-curricular,Art and Design,Business Studies,Citizenship,Design and Technology,English,Geography,History,ICT,Mathematics,MFL French,MFL German,MFL Spanish,Music,Physical Education,PSHE,Religious Education,Science,Something Else
Displayed strings:
Cross-curricular,Citizenship,Art and Design,Business Studies,Design and Technology,English,Geography,History,ICT,Mathematics,MFL French,MFL German,MFL Spanish,Music,Physical Education,PSHE,Religious Education,Science,Something Else
Here, Citizenship has been pushed to the number 2 position.
I've experimented a little, and it seems like there's a bug saying "put things that start with the same letter as the first item after the first item and leave the rest alone". Kind of mystifying. I've tried a bit of debugging by triggering alerts inside the autocomplete plugin code but everywhere i can see, it's using the correct order. it seems to be just when its rendered out that it goes wrong.
Any ideas anyone?
max
EDIT - reply to Clint
Thanks for pointing me at the relevant bit of code btw. To make diagnosis simpler i changed the array of values to ["carrot", "apple", "cherry"], which autocomplete re-orders to ["carrot", "cherry", "apple"].
Here's the array that it generates for stMatchSets:
stMatchSets = ({'':[#1={value:"carrot", data:["carrot"], result:"carrot"}, #3={value:"apple", data:["apple"], result:"apple"}, #2={value:"cherry", data:["cherry"], result:"cherry"}], c:[#1#, #2#], a:[#3#]})
So, it's collecting the first letters together into a map, which makes sense as a first-pass matching strategy. What i'd like it to do though, is to use the given array of values, rather than the map, when it comes to populating the displayed list. I can't quite get my head around what's going on with the cache inside the guts of the code (i'm not very experienced with javascript).
SOLVED - i fixed this by hacking the javascript in the plugin.
On line 549 (or 565) we return a variable csub which is an object holding the matching data. Before it's returned, I reorder this so that the order matches the original array of value we were given, ie that we used to build the index in the first place, which i had put into another variable:
csub = csub.sort(function(a,b){ return originalData.indexOf(a.value) > originalData.indexOf(b.value); })
hacky but it works. Personally i think that this behaviour (possibly coded more cleanly) should be the default behaviour of the plugin: ie, the order of results should match the original passed array of possible values. That way the user can sort their array alphabetically if they want (which is trivial) to get the results in alphabetical order, or they can preserve their own 'custom' order.
What I did instead of your solution was to add
if (!q && data[q]){return data[q];}
just above
var csub = [];
found in line ~535.
What this does, if I understood correctly, is to fetch the cached data for when the input is empty, specified in line ~472: stMatchSets[""] = []. Assuming that the cached data for when the input is empty are the first data you provided to begin with, then its all good.
I'm not sure about this autocomplete plugin in particular, but are you sure it's not just trying to give you the best match possible? My autocomplete plugin does some heuristics and does reordering of that nature.
Which brings me to my other answer: there are a million jQuery autocomplete plugins out there. If this one doesn't satisfy you, I'm sure there is another that will.
edit:
In fact, I'm completely certain that's what it's doing. Take a look around line 474:
// loop through the array and create a lookup structure
for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
/* some code */
var firstChar = value.charAt(0).toLowerCase();
// if no lookup array for this character exists, look it up now
if( !stMatchSets[firstChar] )
and so on. So, it's a feature.

Need help with an AJAX workflow

Sorry I couldn't be more descriptive with the title, I will elaborate fully below:
I have a web application that I want to implement some AJAX functionality into. Currently, it is running ASP.NET 3.5 with VB.NET codebehind. My current "problem" is I want to dynamically be able to populate a DIV when a user clicks an item on a list. The list item currently contains a HttpUtility.UrlEncode() (ASP.NET) string of the content that should appear in the DIV.
Example:
<li onclick="setFAQ('The+maximum+number+of+digits+a+patient+account+number+can+contain+is+ten+(10).');">
What is the maximum number of digits a patient account number can contain?</li>
I can decode the string partially with the JavaScript function unescape() but it does not fully decode the string. I would much rather pass the JavaScript function the faq ID then somehow pull the information from the database where it originates.
I am 99% sure it is impossible to call an ASP function from within a JavaScript function, so I am kind of stumped. I am kind of new to AJAX/ASP.NET so this is a learning experience for me.
First of all, if you're pulling the questions from the db on page load you most likely have all the answers too, so just keep going with your current approach by jamming the answers into the page as your code sample is doing. Unless your FAQ list has thousands and thousands of questions, doing it the "AJAX way" by hitting the db on each click of the list item doesn't give you much here IMO. If it does have that many questions then a straight list is the wrong way to go anyway.
Secondly, two things to keep in mind re your approach:
you're placing html inside an html attribute
the attribute is specifying a javascript function to call
So you need to make sure your "answer" escapes both html and is valid js. By valid js I mean it can't have new lines and must escape quotes properly. For example, the following html - although valid html - won't fire the onclick and you'd just get a js syntax error:
<li onclick="setFAQ('This line's
multi line and has a single quote in it!')"
To account for these I would say HttpUtility.HtmlAttributeEncode in tandem with System.Web.Script.Serialization.JavaScriptSerializer is more appropriate to the markup you've shown.
JavaScriptSerializer json = new JavaScriptSerializer();
string answerString = "This line's\nmulti line and has a single quote in it!";
string onClickJS = String.Format("setFAQ({0})", json.Serialize(answerString));
string onClickAttr = HttpUtility.HtmlAttributeEncode(onClickJs);
Even better, use .NET's ListItem object and lose HtmlAttributeEncode altogether:
ListItem faqItem = new ListItem(questionString);
faqItem.Attributes.Add("onclick", String.Format("setFAQ({0})", json.Serialize(answerString)));
The html portion is escaped automatically for you, plus it's a lot cleaner.
As for your javascript, you don't have to decode anything in setFAQ(). Just take its argument and put it in into you "answer" div:
function setFAQ(answer) {
document.getElementById('answer').innerHTML = answer
}
I think just using HttpUtility.HtmlEncode may solve your problem. I'm not sure I follow completely though : \

Categories