removeStr.indexOf not removing all requested elements - javascript

I am still very much learning Javascript/Google Apps Script, but have created a javascript which takes certain google sheets relating to orders for a business, removes certain data not needed and then creates a list of the remaining ordered items by each item. This has all worked well for the first two of these google sheets, but when I come to the the third, I have an issue in that the removeStr.indexOf is not removing all the data I would expect it too and was therefore hoping someone could tell me where I am going wrong please?
Here is an image of the raw data reduced to fit
From the above the function firstly creates an array which produces the following
Status,NaN,Date Submitted,NaN,Name,NaN,Phone,NaN,Delivery Required?,NaN,Address ,NaN,GLATT SUMMARY,NaN,MH SUMMARY,NaN,GILBERTS SUMMARY,NaN,SMOKED SALMON SUMMARY,NaN,DOVIDS SUMMARY,NaN,Roaster,3,Wrapped Cut Up,1,Wrapped Cut Up Skinned,0,Carcus
,0,Half Hen,0,Mince,0,Lean Mince,2,Chicken Mince,0,Chicken Wings (8),0,Drumsticks (4),1,Thighs (4),0,Breasts (2),4,Pargiot (6),0,Hinds (2),0,Cumberland,2,Burger (4),0,Diced Steak,2,Fairy Steaks (Pack),1,Ribeye Steak,0,Bola,0,Lamb Chops (4),3,Shoulder Chops (2),0,Lamb Shanks (2),0,Shoulder Lamb (off bone),0,Shoulder Lamb (bone in),0,Turkey Thigh,0,Turkey Leg,0,Roaster Crown,0,Roaster in Tin,0,Meatballs 12,0,Meatballs Family,0,Lamb Shwarma,0,Thick Chops (4),0,Salmon 200g,1,Salmon 100g,2,Gefilte,0,Fishball (L),0,Fishball (S),0,ADDITIONAL ITEMS? (subject to availability),NaN
From the above array, the next stage is the to remove the unnecessary elements in two or so stages by firstly removing the not required strings via a removeStr.indexOf and then secondly by removing the NaN's linked to those remove strings. This is done as followed:-
// This array contains strings that needs to be removed from main array for Meat_Fish Order
var removeStr = ['Status' ,'Date Submitted' ,'Name' , 'Phone' , 'Delivery Required?' , 'Address ', 'GLATT SUMMARY' , 'MH SUMMARY' ,'GILBERTS SUMMARY' , 'SMOKED SALMON SUMMARY' , 'DOVIDS SUMMARY' , 'ADDITIONAL ITEMS? (subject to availability)'];
ordered = ordered.filter(function(val){
return (removeStr.indexOf(val) == -1 ? true : false)
});
var ordered = ordered.filter(function(value) {
return !Number.isNaN(value);
});
The above removeStr.indexOf is semi successfully, but for some reason is not removing Address, SMOKED SALMON SUMMARY and DOVIDS SUMMARY, as you can see below.
Address ,SMOKED SALMON SUMMARY,DOVIDS SUMMARY,Roaster,3,Wrapped Cut Up,1,Wrapped Cut Up Skinned,0,Carcus
,0,Half Hen,0,Mince,0,Lean Mince,2,Chicken Mince,0,Chicken Wings (8),0,Drumsticks (4),1,Thighs (4),0,Breasts (2),4,Pargiot (6),0,Hinds (2),0,Cumberland,2,Burger (4),0,Diced Steak,2,Fairy Steaks (Pack),1,Ribeye Steak,0,Bola,0,Lamb Chops (4),3,Shoulder Chops (2),0,Lamb Shanks (2),0,Shoulder Lamb (off bone),0,Shoulder Lamb (bone in),0,Turkey Thigh,0,Turkey Leg,0,Roaster Crown,0,Roaster in Tin,0,Meatballs 12,0,Meatballs Family,0,Lamb Shwarma,0,Thick Chops (4),0,Salmon 200g,1,Salmon 100g,2,Gefilte,0,Fishball (L),0,Fishball (S),0
I thought the issue was down possible to case, additional spacing, or something like that, but have matched exactly and still no joy.
As well as sorting this would be good to know if there is anything within Javascript which is of use to take away an potential issues with case sensitivity and additional spacing. Is there anything?
Big thanks in advance

to correct errors of whitespace and capital letters let's standardize all texts before:
const standardize = val => {
if (typeof val === 'string') return val.replace(/\s/g, '').toLowerCase()
return val
}
const standardizedRemoveStr = removeStr.map(standardize)
const res = ordered.filter(val => {
return !standardizedRemoveStr.includes(standardize(val)) && !Number.isNaN(val)
})

Related

How could a viable transformation look like that does convert a product-name into a valid HTML id-attribute value? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
There is a list of product data. Each product item has a string-type name-property.
How could a viable transformation look like that does convert a product-name into a valid HTML id-attribute value?.
Viable means that a transformation is build in a way that there should be almost no chance for generating identical id's from two different but similar constructed product names.
The naming of common products looks like this ...
"2-inch leg extension"
"2' x 8' Overhead Garage Storage Rack"
"4 Drawer Base Cabinet 16-1/2"W x 35"H x 22-1/2"D"
"24" Long Tool Bar w/ Hooks Accessory"
Transformed validly the above list might look like that ...
"z2-inchlegextension"
"z2x8OverheadGarageStorageRack"
"z4DrawerBaseCabinet16-12Wx35Hx22-12D"
"z24LongToolBarwHooksAccessory"
One could consider providing a prefix (e.g. "z") to the to be generated id in oder to make it a valid HTML id-attribute.
I'm not familiar with replacement techniques that assure results which will be repeatable consistent.
How could a possible transformation approach look like?
You can try this-
const data = [
"2-inch leg extension",
"2' x 8' Overhead Garage Storage Rack",
"4 Drawer Base Cabinet 16-1/2\"W x 35\"H x 22-1/2\"D",
"24\" Long Tool Bar w/ Hooks Accessory"
];
const res = data.map(str => str.replace(/[^a-z\d\-_]/ig, ''));
console.log(res);
If you need any prefix with the ID then add it like-
const prefix = 'Z';
const res = data.map(str => prefix + str.replace(/[^a-z\d\-_]/ig, ''));
The simplest answer that fulfills your requirement:
string.replace(/[^A-Za-z]/g, "");
If there are no letter characters this will result in an empty string. But since IDs need to start with letters anyway, you need special handling for cases where your product names have no letters in them
The following approach creates configurable identifiers.
It also preserves as much information of a given product name as possible in order to prevent the accidental creation of identifier duplicates.
It does so by translating the string patterns of technical measures, units and terms as much as it could be anticipated from the examples provided by the OP.
const productNameList = [
"2-inch leg extension",
"2' x 8' Overhead Garage Storage Rack",
'4 Drawer Base Cabinet 16-1/2"W x 35"H x 22-1/2"D',
'24" Long Tool Bar w/ Hooks Accessory'
];
function createIdentifier(str) {
const config = this;
const prefix = config.prefix || '_';
const separator = config.separator || '';
const id = [prefix, str
// replace foot symbol that follows immediately after a digit
.replace((/([\d])'/g), `$1${ separator }Ft`)
// replace inch symbol (double quote character)
.replace((/"/g), `${ separator }In${ separator }`)
// replace times character enclosed by word boundaries
.replace((/\bx\b/g), 'Times')
// replace digit connector, a minus symbol enclosed by digits
.replace((/([\d])-([\d])/g), `$1${ separator }And${ separator }$2`)
// replace division symbol that is enclosed by digits
.replace((/([\d])\/([\d])/g), `$1${ separator }By${ separator }$2`)
// uppercase any character that follows a word boundary
.replace((/\b([\w])/g), ([$1]) => $1.toUpperCase())
// replace/delete all non word characters.
.replace((/[\W]+/g), separator)
].join('');
return ((separator && id.toLowerCase()) || id);
}
console.log(
productNameList,
' => HTML id attribute => ',
productNameList.map(createIdentifier, { prefix: 'pid_' })
);
console.log(
productNameList,
' => HTML id attribute (long) => ',
productNameList.map(createIdentifier, { prefix: 'pid_', separator: '-' })
);
console.log(
productNameList,
' => valid JS variable name => ',
productNameList.map(createIdentifier)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

convert number into number and quantifier

How would I convert something like 1200000 to £1.2m but also convert 2675000 to £2.675m
i can get the second one to work but the first one comes out as £12m rather than £1.2m
I have the number in a variable so.
salePrice.toString().replace(/0+$/g, '').replace(/\B(?=(\d{3})+(?!\d))/g, '.')}m
how would i change the second replace to work as I guess it is that one that is causing the issue.
as long as this passes
1200000
1220000
1222000
1222200
1222220
1222222
1020000
1022200
so on and so forth all of them need to be able to pass.
You have Number.prototype.toFixed() option available.
const data = [
2675000,
1200000,
1220000,
1222000,
1222200,
1222220,
1222222,
1020000,
1022200
];
const formatted = data.map(x=> (x/1000000).toFixed(3).replace(/0+$/g, '')); // ["2.675", "1.2", "1.22", "1.222", "1.222", "1.222", "1.222", "1.02", "1.022"]
I haven't included the part with the currency, because you had that figured out already. Shilly's answer is really beautiful. I'm simply proposing another solution, which is a bit shorter.
You divide them by the precision you need. I would advice to keep numbers as numbers as long as possible, since strings used as numbers follow text rules instead of math rules, so you'd have to parse them back to numbers to do anything meaningful apart from formatting the output.
const data = [
2675000,
1200000,
1220000,
1222000,
1222200,
1222220,
1222222,
1020000,
1022200
];
const format_currency = ( prefix, value, precision, suffix ) => `${ prefix }${ value / precision }${ suffix }`;
const million = {
symbol: 'm',
value: 1000000
};
const pounds = '£';
const results = data.map( entry => format_currency( pounds, entry, million.value, million.symbol ));
console.log( results );

set expected result as true when find in a string partly correct protractor

Hello everyone I got following code:
it('Search for string', function () {
var MySearch = element(by.model('searchQuery'));
MySearch.sendKeys('Apple Pomace');
expect(MySearch.getAttribute('value')).toBe('Apple Pomace');
element(by.buttonText('Search')).click();
//browser.pause();
var optionTexts = element.all(by.repeater('product in products')).map(function (Options) {
return Options.getText();
});
optionTexts.then(function (array){
expect(array).toContain("Apple Pomace");
});
});
then I get as result:
[ 'Apple Pomace\nFinest pressings of apples. Allergy disclaimer: Might contain traces of worms. Can be sent back to us for recycling.\n0.89' ]
now I want to check if the string contains Apple Pomace
I have tried following code:
expect(array).toContain('Apple Pomace');
then I get:
Expected [ 'Apple Pomace
Finest pressings of apples. Allergy disclaimer: Might contain traces of worms. Can be sent back to us for recycling.
0.89' ] to contain 'Apple Pomace'. <Click to see difference>
how do I set the test to true even if the whole string doesn't match my result?
or validate the string to the first "\" ?
code
Thank you in advance
First of all element.all(by.repeater('product in products')).getText() will return array of strings.If you use toContain matcher on the array, it will check for the whole string to be present in the array.
In your case, you need to check if the entire array has any string that matches the word Apple Pomace. To achieve this, you need to transform the result array into a string and then apply toContain matcher on it.
var displayedResults = element.all(by.repeater('product in products')).getText()
.then(function(resultArray){
return resultArray.join(); // will convert the array to string.
})
expect(displayedResults).toContain("Apple Pomace");
Hope this might help you!

Multiple words search and calculation algorithm (Angular/Javascript)

I'm loading json file from database with two fields words and grade. Each word is graded for example true has 1 while lie has -1. Then i take input from text filed and i need to grade it based on grades from JSON file and then calculate score by summarizing the grades, but i just can't seem to find the way to do that. Words that are not in file are not being calculated.
I tried string.search match but it's to complicated and in the end i couldn't get result the way i wanted. I tried array searches same thing. I searched for on line solution, but no one has done anything similar so i can't copy it.
JSON
[
{"word":"true","grade":1},
{"word":"hate","grade":-1},
{"word":"dog","grade":0.8},
{"word":"cat","grade":-0.8}
]
String
"Dogs are wonderful but i prefer cats, cats, i can not lie although dog is a true friend".
The first thing I'd do is turn your JSON data into a map which can easily be searched - key would be the word, and value the grade:
var json = [
{"word":"true","grade":1},
{"word":"hate","grade":-1},
{"word":"dog","grade":0.8},
{"word":"cat","grade":-0.8}
];
var map = json.reduce(function(p,c){
p.set(c.word.toLowerCase(),c.grade);
return p;
}, new Map());
console.log(...map);
Then, its just a case of splitting your string, whilst also calculating the total score - again reduce can be used
var json = [
{"word":"true","grade":1},
{"word":"hate","grade":-1},
{"word":"dog","grade":0.8},
{"word":"cat","grade":-0.8}
];
var map = json.reduce(function(p,c){
p.set(c.word.toLowerCase(),c.grade);
return p;
}, new Map());
var input = "Dogs are wonderful but i prefer cats cats i can not lie although dog is a true friend";
var score = input.split(' ').reduce(function(p,c){
var wordScore = map.get(c.toLowerCase()) || 0;
return p + wordScore;
},0);
console.log(score);
Note that I have manually removed punctuation in the above input - I'll leave that as an exercise for you.
Also note that "cats" != "cat" so some of your words wont be found!
Let's first think of the algorithm. Two options:
Search and count the input string as many times as number of words in your JSON, or
Check each word in your input string against the JSON contents.
Since the JSON length is known and (I presume) shorter than the possible input string, I would tend to prefer option 2.
Now, after selecting option 2, you need to split the input string into words and create an array containing one word each entry of the array.
You can achieve this using the mystring.split(" ") method. This, of course, does not take into account punctuations, but you can handle this using the same method.
Now, you can add to each entry in your JSON a field to count the number of appearances of each entry in the JSON within the string.
Finally, you sum the product of the counters and the grade.
console.log((function(rules, str) {
var sum = 0;
Array.prototype.forEach.call(rules, function(rule) {
var match = str.match(rule.regexp);
match && (sum += str.match(rule.regexp).length * rule.grade);
console.log([rule.regexp, match&&match.length, rule.grade, match&&match.length * rule.grade, sum]);
});
return sum;
})([{
"regexp": /true/g,
"grade": 1
}, {
"regexp": /hate/g,
"grade": -1
}, {
"regexp": /dog/g,
"grade": 0.8
}, {
"regexp": /cat/g,
"grade": -0.8
}], "Dogs are wonderful but i prefer cats, cats, i can not lie although dog is a true friend"));
i use regexp rather than string, u can use string and convert to regex at run time, hope this would help

How can I put names into title case in JavaScript?

I've been looking around on how to use JavaScript to set names to proper case, e.g. george mchall would become George McHall. I was able to find a write up on Codeproject on how to do this, as well as a person that intended it to do this:
function toProperCase(s){
return s.toLowerCase().replace( /\b((m)(a?c))?(\w)/g,
function($1, $2, $3, $4, $5) {
if($2){
return $3.toUpperCase()+$4+$5.toUpperCase();
}
return $1.toUpperCase();
});
}
This allows for what I'm looking for. But I need to be able to extend it further and add additional cases.
I found another page on John Gruber's site doing title case, but I'm only looking at doing names.
So, does anyone have an idea on extending it? I'm really just looking for a point in the right direction.
Edit:
Since I seem to be hitting a wall here, maybe someone has a way to do it server side. This is at least for now using ColdFusion for the server side. I've seen a C# implementation, but I'm not able to move to C# at the moment.
Combining a few answers from similar posts:
var selElem = document.getElementById("fromName");
selElem.addEventListener("change", function() {
document.getElementById("result").innerHTML = properName(selElem.value);
});
function properName(name) {
return ("" + name.replace(/[^\s\-\']+[\s\-\']*/g, function(word) {
return word.charAt(0).toUpperCase() + word.substr(1).toLowerCase();
}).replace(/\b(Van|De|Der|Da|Von)\b/g, function(nobiliaryParticle) {
return nobiliaryParticle.toLowerCase();
}).replace(/Mc(.)/g, function(match, letter3) {
return 'Mc' + letter3.toUpperCase();
}));
}
<p>
Choose a name to see it properly capitalised:
</p>
<select id="fromName">
<option>Select a name</option>
<option>EMMA HURST</option>
<option>CHRIS HINDI</option>
<option>OSCAR GRENFELL</option>
<option>JIM CASEY</option>
<option>MEOW-LUDO DISCO GAMMA MEOW-MEOW</option>
<option>PAT SHEIL</option>
<option>NOEL MCFARLANE</option>
<option>CHRIS MCLACHLAN</option>
<option>ANTHONY ALBANESE</option>
<option>DAVID VAN GOGH</option>
<option>JAMIE ELVY</option>
</select>
<p>Result: <span id="result"></span></p>
How about this:
if (str==str.toLowerCase() || str==str.toUpperCase())
str = str.toTitleCase();
Otherwise, leave it well alone!!!
Edit: You could optionally split the string to weed out people holding the shift key for too long, like SMith.

Categories