JavaScript: extract column headers from table configuration string - javascript

I need help grabbing some string operation in Javascript. I have a sample string as
var str = 'Supplier^supp^left^string*Spend (USD MM)^spend^right^number^5';
The string is basically a configuration for a portlet for two columns as Supplier and Spend..I have to get the column names from this string. Each star follows a new column config. In this case there are configs for only 2 columns and hence only 1 star exists in my string. Supposedly if there are 2 columns the string will look like
var str = 'Supplier (Name)^Supplier^left^string*Spend (USD MM)^Spend^right^number^5*Location (Area)^Loc^right^string^*Category ^Categ^right^string';
So from the above string i had written a logic to get the desired string as
after the 2nd caret i want 'Supplier'(1stcolumn data name and not 'Supplier (Name) which is a display name) ,(Moving to 2nd column after the star)after the 2nd caret 'Spend'.Similarly 'Loc' (3rd column) and 'Categ' (4th column). Can anybody help me achieve this? Here is what i had written
function getColNamesfromConfig(str) {
var i = str.indexOf('^');
var tmpCatStr = str.slice(i + 1);
var catField = tmpCatStr.slice(0, tmpCatStr.indexOf('^'));
var j = tmpCatStr.indexOf('*');
var tmpStr = tmpCatStr.slice((j + 1));
var k = tmpStr.slice(tmpStr.indexOf('^') + 1);
var valField = k.slice(0, k.indexOf('^'));
return { categoryField: catField, valueField: valField };
}

You can use split()
str.split('*')[0].split('^')[1]
the above code will give you
Supplier
Check the following link

Or use a regular expression:
function headers(s) {
var re = /([^^]+)(?:[^*]+[*]?)?/g, names=[];
while (match = re.exec(s)) {
names.push(match[1]);
}
return names;
}
Outputs
["Supplier","Spend (USD MM)","Location (Area)","Category "]
and
["Supplier (Name)","Spend (USD MM)","Location (Area)","Category "]
for your two examples
See this in action (JSFiddle).

Related

Using JS to sum a column of values from an external text file containing donation histories of a db of donors

I need some assistance figuring out how to sum a column of dynamic totals that could be a positive or negative dollar amount, or an indication of stock shares.
I have a tab-delimited text file of donor contributions for that I am matching up against a CSV file of other related customer data that I am using to create a statement letter which will show a "donation history" of a particular donor. Each donor has a different amount of donations, and to complicate things, the column of data for a particular donation record could show either "$1,000.00" or "($1,000.00)" or "2 Shares APPL". The number with the parentheticals is of course, representing a negative number.
At the end of this column, I need to show a string that will read either "Total: $1,000.00," or if any of the donation history contains a donation record that included shares of stock the returned string will simply read, "$1,000.00 & Stock."
I have been racking my brain trying to come up with the JS rule that can achieve this. I have the JS rule that is generating the donation history correctly, but summing the donation amount column is causing me to go crazy...
Here is the JS for generating my donation history list in the letter (this seems to be working fine):
var contributionList = new ExternalDataFileEx("/~wip/248839 Frontiers/Master Data/Double Data proof.txt", "\t");
var donor_id = Field("Supporter");
var lb = "<br>\n";
var matches = new Array();
for (var i = 0; i <= contributionList.recordCount; i++) {
var idVariable = contributionList.GetFieldValue(i, "Supporter");
var dateVariable = contributionList.GetFieldValue(i, "Donation Date");
var ministryVariable = contributionList.GetFieldValue(i, "Ministry Designation");
var giftVariable = contributionList.GetFieldValue(i, "Donation Amount");
var tsSettings = "<p tabstops=19550,Right,,;29600,Left,,;>";
var ts = "<t>";
if (donor_id == idVariable)
matches.push(tsSettings + dateVariable + ts + giftVariable + ts + ministryVariable);
}
//return matches;
return matches.join(lb);
Now here is the JS code that is not working just fine. I am trying to tally the donation amount column, it only returns "Total: $0.00 & Stock" every time (I have tried to explain my thought process via comments):
var contributionList = new ExternalDataFileEx("/~wip/248839 Frontiers/Master Data/Double Data proof.txt", "\t");
var donor_id = Field("Supporter");
for (var i = 0; i <= contributionList.recordCount; i++) {
var idVariable = contributionList.GetFieldValue(i, "Supporter");
var giftVariable = contributionList.GetFieldValue(i, "Donation Amount");
var sum = 0;
var shares = 0;
var tsSettings = "<p tabstops=19550,Right,,;29600,Left,,;>";
var ts = "<t>";
var totalStr = "Total ";
var stockStr = " & Stock";
var totalFormatted = FormatNumber("$#,###.00", Math.max(0, StringToNumber(sum)));
// Match data from linked file to current Supporter
if (donor_id == idVariable) {
// Look at current record and see if it contains the word "Share(s)"
// or not and act accordingly
if (giftVariable.match(/(^|\W)share($|\W)/i) || giftVariable.match(/(^|\W)shares($|\W)/i)) {
// Turn switch "on" if donation amount is a share or shares so
// we can have the " & Stock" appended to our string.
shares = 1;
// Because this donation is/are shares, we must "zero" this
// amount to make the math work when we sum everything up...
giftVariable = 0;
// This is where we are keeping our running total...
sum += giftVariable[i];
} else {
// This record was not a donation of share(s) so we now have to
// determine whether we are dealing with postive or negative numbers
// and then strip out all of the non-number characters, remove and
// replace the () whis just a "-," leaving us with a number we can
// work with...
// If number has parenthesis, then deal with it...
if (giftVariable.indexOf("(")) {
// Strip out all the ()$, characters...
giftVariable = giftVariable.replace(/[()$,]/g,"")
// Append the minus sign to the number...
giftVariable = "-" + giftVariable;
sum += giftVariable[i];
} else {
giftVariable = giftVariable.replace(/[$,]/g,"");
sum += giftVariable[i];
}
}
}
}
// Return Total...
if (shares == 1) {
return tsSettings + totalStr + ts + totalFormatted + stockStr;
} else {
return tsSettings + totalStr + ts + totalFormatted;
}
Any assistance would be greatly appreciated!
The problem (and code) needs to be broken into smaller, atomic steps. From your description it sounds like you should:
load a text file into memory
for each line in the file
extract: {
donor_id
charity
gift
and store the results in a contributions dictionary
for each item in the contributions dictionary
transform gift string into {
dollarAmount: float with a default of 0.0
stock: name with a default of ""
}
create an empty dictionary called totals
each item will have the shape {
id
dollarAmount as a float
stocks an an array
}
for each item in the contributions dictionary
lookup the id in the totals dictionary
if it exists
totals[id].dolarAmount += item.dollarAmount
totals[id].stocks.push(item.stock)
otherwise
totals[id].dollarAmount = item.dollarAmount
totals[id].stocks = [item.stock]
normalize your charities
for each item in totals dictionary
remove any empty strings from item.charities
create your report
for each item in totals dictionary
write`${item.id} donated `${item.dollarAmont}` ${item.stocks.length > 1 ? 'and stock' : ''
I believe you are trying to do too many things at once. Instead, the goal should be to normalize your data before you attempt to perform any calculations or aggrgrations, then normalize your aggregrations before writing your summaries or reports.
I would also stay away from using any direct string manipulation. You should have a dedicated function whose only purpose is to take a string like "($20.34) and 1 share of APPL" and return either 20.34, -20.34, or 0.0. And a different function whose only purpose is to take the same string and return either true or false is stock was present.

TypeError: Cannot find function "sort" in "object"... but the said object is supposed to be a string according to google docs

TL:DR
According to the google docs, getResponseText() should return a string... but I get a message that claims it is an object when I try to sort it.. huh?
TypeError: Cannot find function sort in object
I was under the impression that a javascript string sort of works like an array, and it seems to behave like one because string[0] returns the first letter of a string..
DETAILS:
here is the sheet I am working
Hello everyone, I have a very unique situation where I need to update dirty strings (courtesy of an undesirable OCR import).
I have created a function that does the job but needs additional functionality.
Currently, the process goes like this:
enter your desired string
each cell (in your selection) is checked for that string
cells are updating with desired string if the match is over 50% alike
the check works like this:
compare the first letter of desired string (txtT[0])
against the first letter of target cell (valT[0])
compare additional letters [x] up to the length of the longest string
for example:
desired string = "testing"
target cell = "t3st1ng"
the loop goes like this:
create a point system do to math
(total points = length of longest string)
compare t and t ... if matching, add one point (+1 in this case because it matches)
compare e and 3 ... if matching, add one point (+0 in this case because it does not match)
compare s and s ... if matching, add one point (+1 in this case because it matches)
compare t and t ... if matching, add one point (+1 in this case because it matches)
compare i and 1 ... if matching, add one point (+0 in this case because it does not match)
compare n and n ... if matching, add one point (+1 in this case because it matches)
compare g and g ... if matching, add one point (+1 in this case because it matches)
points earned/total points = % of alike
The problem with this system is that if is based on the position of the letters in each string.
This causes problems when comparing strings like "testing" and "t est ing"
I tried to update it so that the first thing it does is SORT the string alphabetically, ignoring all special characters and non alphabetical characters.
That's when I came across an error:
TypeError: Cannot find function sort in object testing.
This does not make sense because my desired string is a string. See code where it says "this is where i get my error":
According to the google docs, getResponseText() should return a string... but I cannot call the sort method on the string.. which makes no sense!
function sandboxFunction() {
try {
var ui = SpreadsheetApp.getUi();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var as = ss.getActiveSheet();
var ar = as.getActiveRange();
var sv = ui.prompt('enter desired string');
var txt = sv.getResponseText();
var txtT = txt.trim();
txtT = txtT.replace(/ /g, ''); //this is the trimmed comparison string
txtT = txtT.sort(); //***this is where I get my error***
ui.alert(txtT);
var vals = ar.getValues();
for (var r = 0; r < vals.length; r++) {
var row = vals[r];
for (var c = 0; c < row.length; c++) {
var val = row[c];
var valT = val.trim();
valT = valT.replace(/ /g, ''); // this is the trimmed comparison cell
ui.alert(valT);
//this is where we test the two
//test length
var tl = txtT.length;
var vl = valT.length;
if (vl < tl) {
ui.alert("different lengths.. applying fix");
for (vl; vl < tl; vl++) {
valT = valT.concat("x");
ui.alert(valT);
}
}
else if (tl < vl) {
ui.alert("different lengths.. applying fix");
for (tl; tl < vl; tl++) {
txtT = txtT.concat("x");
ui.alert(txtT);
}
}
if (valT.toUpperCase() == txtT.toUpperCase()) {
ui.alert("your strings match");
}
else {
var total = txtT.length;
var pts = 0;
for (var x = 0; x < total; x++) {
if (valT[x] == txtT[x]) {
pts++;
}
}
if (pts / total >= 0.5) {
ui.alert("at least 50% match, fixing text");
vals[r][c] = txt;
}
}
}
}
ar.setValues(vals);
}
catch (err) {
ui.alert(err);
}
}
You can't sort a string in that way, sort is a method of arrays.
You can convert your string to an array, later you can sort
var txtT = "This is a string".trim();
txtT = txtT.replace(/ /g, ''); //this is the trimmed comparison string
var txtArray = txtT.split(''); // Convert to array
var txtSorted = txtArray.sort(); // Use sort method
console.log(txtSorted);
See sort() docs

Mask a portion of a String using RegExp

I'm trying to mask a portion of a string using JavaScript.
e.g. Mask second and third segment of credit-card number like this using regex:
4567 6365 7987 3783 → 4567 **** **** 3783
3457 732837 82372 → 3457 ****** 82372
I just want to keep the first 4 numbers and the last 5 characters.
This is my first attempt: /(?!^.*)[^a-zA-Z\s](?=.{5})/g
https://regex101.com/r/ZBi54c/2
You can try this:
var cardnumber = '4567 6365 7987 3783';
var first4 = cardnumber.substring(0, 4);
var last5 = cardnumber.substring(cardnumber.length - 5);
mask = cardnumber.substring(4, cardnumber.length - 5).replace(/\d/g,"*");
console.log(first4 + mask + last5);
You could slice the first four digits and apply a replacement for the rest.
console.log(
['4567 6365 7987 3783', '3457 732837 82372'].map(
s => s.slice(0, 4) + s.slice(4).replace(/\d(?=.* )/g, '*')
)
);
The answer apparently satisfies the OP. Here is another solution using only Regexes:
function starry(match, gr1, gr2, gr3) {
var stars = gr2.replace(/\d/g, '*');
return gr1 + " " + stars + " " + gr3;
}
function ccStarry(str) {
var rex = /(\d{4})\s(\d{4}\s\d{4}|\d{6})\s(\d{4}|\d{5})/;
if (rex.test(str))
return str.replace(rex, starry);
else return "";
}
var s1 = "4567 6365 7987 3783";
var s2 = "3457 732837 82372";
var s3 = "dfdfdf";
console.log(ccStarry(s1));
console.log(ccStarry(s2));
console.log(ccStarry(s3));
This ensures that the pattern matches before trying any replacements. For example, in the third test case, it returns an empty string. The pattern can be updated to match other credit card patterns besides the ones given in the question.
I would like to elaborate more on the answer from #Nina Scholz, I use .slice() in the following sample code for masking the variable in 2 condition.
Just a simple variable var n = '12345567890'
Array object
// Single number
var n = '601115558888';
var singleNumber = n.slice(0, 4) + n.slice(4, n.length -4).replace(/\d/g,'*') + n.slice(n.length -4);
console.log(singleNumber);
// array of object
var obj = [{
contacts_name: 'Jason',
contacts_num : '651231239991'
},
{
contacts_name: 'King',
contacts_num : '60101233321'
}];
// Mask for the middle number, showing the first4 number and last4 number
// and replace the rest number with *
var num = obj.map((element, index) =>
element.contacts_num.slice(0,4)
+ element.contacts_num.slice(4, element.contacts_num.length-4).replace(/\d/g, '*')
+ element.contacts_num.slice(element.contacts_num.length -4)
);
console.log(num);
If it's JavaScript doing the regex masking, you've already failed because JS should never need to know the original card number, except when you've just received it from the user and are sending it to the server for the first time, in which case you shouldn't be masking it anyway so the user can check for typos.
I can't really help you there, you've already failed in the worst way.
Server-side, if the number is already broken into spaces*, then one option is: (in PHP but the same idea applies to all)
$parts = explode(" ",$fullnumber);
$first = array_shift($parts);
$last = array_pop($parts);
$middle = implode(" ",$parts);
$mask = preg_replace("/\d/","*",$middle);
$result = "$first $mask $last";
* it shouldn't be

Get String value between two strings through javascript

I want to get the string value between ";L0|" and ";GTSet" from the following type of strings.
var test = "GP0|#9d72d96c-407f-4e45-b2e6-9361faf5808a;L0|#09d72d96c-407f-4e45-b2e6-9361faf5808a|Travel;GTSet|#ac96f075-b7d2-4e90-8dc2-da8875f395fc";
var test2 = "GP0|#15a06b93-f7aa-4dda-b0d6-7bf2d2905f27;L0|#015a06b93-f7aa-4dda-b0d6-7bf2d2905f27|Special Event;GTSet|#ac96f075-b7d2-4e90-8dc2-da8875f395fc";
Here is what i have done already.
var str = test2.match(";L0|" + "(.*?)" + ";GTSet");
alert(str[1]);
and this returns a string from the very beginning till the ";GTSet"
Jsfiddle link here
I guess you are getting this value from SharePoint Search results, right? If so, according to Automatically created managed properties in SharePoint Server 2013:
Data format for Managed Metadata.
To query for items tagged with a Managed Metadata field, you have to
use the Unique Identifier for each label. You can find the Unique
Identifier for each term in a term set in the Term Store Management
Tool, on the GENERAL tab. In addition, the data format that is used in
the query has to specify from which level in the term set the query
should apply. This specification is set by adding one of the following
prefixes to the Unique Identifier:
To query for all items that are tagged with a term: GP0|#
To query for all items that are tagged with a child of term: GPP|#
To query for all items that are tagged with a term from a term set: GTSet|#
Based on this information the following example demonstrates how to parse search result value for managed metadata:
function parseTaxonomySearchResultValue(val){
var taxValue = {TermSetGuids: [], TermValues: []};
var parts = val.split(';');
parts.forEach(function(part){
if (part.startsWith("GP0|#")) //term?
{
var termGuid = part.replace("GP0|#", "");
taxValue.TermValues.push({ TermGuid: termGuid});
}
else if (part.startsWith("GTSet|#")) //term set?
{
taxValue.TermSetGuids.push(part.replace("GTSet|#", ""));
}
else if (part.startsWith("L0|#")) //Term with label?
{
var termParts = part.replace("L0|#0", "").split('|');
var termGuid = termParts[0];
var termLabel = termParts[1];
var result = taxValue.TermValues.filter(function(tv){
return tv.TermGuid == termGuid;
});
if (result.length == 0)
taxValue.TermValues.push({TermGuid : termGuid, Label : termLabel});
else
result[0].Label = termLabel;
}
});
return taxValue;
}
//Usage
var taxValue = 'GP0|#9d72d96c-407f-4e45-b2e6-9361faf5808a;L0|#09d72d96c-407f-4e45-b2e6-9361faf5808a|Travel;GTSet|#ac96f075-b7d2-4e90-8dc2-da8875f395fc';
var taxValue = parseTaxonomySearchResultValue(taxValue);
document.getElementById('output').innerHTML = "Term info:<br/>" + "Guid= " + taxValue.TermValues[0].TermGuid + "<br/> Label= " + taxValue.TermValues[0].Label;
<div id='output'/>

Find two numbers in a string

This is a follow on from my previous question which can be found here
Link For Previous Question
I am posting a new question as the answer I got was correct, however my next question is how to take it a step further
Basically I have a string of data, within this data somewhere there will be the following;
Width = 70
Void = 40
The actual numbers there could be anything between 1-440.
From my previous question I found how to identify those two digits using regular expression and put them into separate fields, however, my issue now is that the string could contain for example
Part Number = 2353
Length = 3.3mm
Width = 70
Void = 35
Discount = 40%
My question is;
How do I identify only the Width + Void and put them into two separate fields, the answer in my previous question would not solve this issue as what would happen is in this example I would have an array of size 4 and I would simply select the 2nd and 3rd space.
This is not suitable for my issue as the length of array could vary from string to string therefore I need a way of identifying specifically
Width = ##
Void = ##
And from there be able to retrieve the digits individually to put into my separate fields
I am using JavaScript in CRM Dynamics
A simpler option is to convert the whole string into an object and get what you need from that object.
str = "Part Number = 2353\n" +
"Length = 3.3mm\n" +
"Width = 70\n" +
"Void = 35\n" +
"Discount = 40%\n";
data = {};
str.replace(/^(.+?)\s*=\s*(.+)$/gm, function(_, $1, $2) {
data[$1] = $2;
});
alert(data['Width']);
Width\s+=\s+(\d+)|Void\s+=\s+(\d+)
You can try this.Grab the capture.See demo.
http://regex101.com/r/oE6jJ1/31
var re = /Width\s+=\s+(\d+)|Void\s+=\s+(\d+)/igm;
var str = 'Part Number = 2353\n\nLength = 3.3mm\n\nWidth = 70\n\nVoid = 35\n\nDiscount = 40%';
var m;
while ((m = re.exec(str)) != null) {
if (m.index === re.lastIndex) {
re.lastIndex++;
}
// View your result using the m-variable.
// eg m[0] etc.
}
You can use this regex for matching input with Width and Void in any order:
/(\b(Width|Void) += *(\d+)\b)/
RegEx Demo
Your variable names and values are available in captured groups.

Categories