Can a RegEx be created to pull the same pattern over and over?
https://regex101.com/r/BEOHLh/2/
Tried something like this too:
.* [(.*?)='(.*?)']{0-5}.*
to allow for everything in square brackets to repeat.
I could parse it without RegEx, but seem like RegEx would be the best. I'm converting some WordPress shortcodes to a NodeJS based system. Need to extract id and label (either one may be optional), so here are three test cases and the code I tried.
var testArray = ["[include_word id='110']", "[include_word label='bah']", "[include_word id='987' label='bah-beh']"];
testArray.forEach (processArrayItemRegex);
function processArrayItemRegex (item, index) {
console.log ("index:" + index + " item:" + item);
//var regexPattern = /.*id='(<id>.*?)'.*label='(<label>.*?)'.*/g;
//var regexPattern = /.*(?:id='(.*?)').*(?:label='(.*?)').*/g;
var regexPattern = /.* (.*?)='(.*?)'.*/g;
//const { groups: segments } = item.match(regexPattern);
var segments = item.match(regexPattern);
console.dir(segments, { depth: null });
//console.log(segments);
id = segments[0];
label = segments[1];
console.log("id=" + id + " label=" + label);
}
Current output:
index:0 item:[include_word id='110']
[ '[include_word id=\'110\']' ]
id=[include_word id='110'] label=undefined
index:1 item:[include_word label='bah']
[ '[include_word label=\'bah\']' ]
id=[include_word label='bah'] label=undefined
index:2 item:[include_word id='987' label='abc']
[ '[include_word id=\'987\' label=\'abc\']' ]
id=[include_word id='987' label='abc'] label=undefined
The code below works to convert it to JSON and let's me access the variables, it's just not as elegant as I would like:
function processArrayItem (item, index) {
console.log ("index:" + index + " item:" + item);
//remove unneeded wrappers
item = item.replace("include_word ","")
item = item.replace("[","{").replace("]","}");;
item = item.replace(/'/g, '"');
item = item.replace('id=','"id":');
item = item.replace('label=','"label":');
item = item.replace('transliteration=','"transliteration"');
var itemObj = JSON.parse(item);
console.log("id=" + itemObj.id + " label=" + itemObj.label);
}
If I understand correctly, the thing you're missing is the matchAll function.
Try this as a starting point:
for (let match of "[include_word id='987' label='bah-beh']".matchAll(
/(\S+)='(\S+)'/g
)) {
console.log({ key: match[1], value: match[2] });
}
I am not sure whether this is what you want,
testArray.forEach (processArrayItemRegex);
function processArrayItemRegex (item, index) {
console.log ("index:" + index + " item:" + item);
var regexPattern = /(\S+)='(\S+)'/g;
//console.log(regexPattern);
var id = label = 'undefined';
var segments ;
while ((segments = regexPattern.exec(item)) != null)
{
//console.dir(segments , { depth: null });
var key = segments [1];
var value = segments [2];
if (key == 'id')
id = value;
if (key == 'label')
label = value;
};
console.log("id=" + id + " label=" + label);
}
Console output:
index:0 item:[include_word id='110']
id=110 label=undefined
index:1 item:[include_word label='bah']
id=undefined label=bah
index:2 item:[include_word id='987' label='bah-beh']
id=987 label=bah-beh
Related
I have a popup on a website that displays values from a geoJSON file. Right now, it looks as in the picture below:
This is the current code:
function popUp_cc_210303(f, l) {
var out = [];
if (f.properties) {
var url =
'<a href=/uas_tools/crop_analysis/index.php?crop=Wheat&year=2021&location=Amarillo&sublocation=Irrigation';
var parameters = '';
for (key in f.properties) {
out.push(key + ': ' + f.properties[key]);
parameters += '&' + key.replace(/\ /g, '_') + '=' + f.properties[key];
}
url +=
parameters.replace(/\ /g, '%20') + " target='_blank'>Growth analysis</a>";
out.push(url);
var url2 =
'<a href=/uas_tools/variety_analysis/index.php?crop=Wheat&year=2021&location=Amarillo&sublocation=Irrigation';
url2 += " target='_blank'>Variety analysis</a>";
out.push(url2);
l.bindPopup(out.join('<br />'));
}
}
I am trying to use out.push(key+": "+f.properties[key].toFixed(2)); but it does not work.
This is the geoJSON file structure
{ "type": "Feature", "properties": { "Row name": "row-1", "Col": "1", "plot_num": "?436", "plot_name": "?AOBS", "join_key": "?AOBS?436", "CC201014": 0.0, "CC201104": 0.0016344676538850001, "CC201120": 0.56401258728343395, "CC201217": 8.3524346613304221, "CC210113": 7.7746312091202094, "CC210224": 9.7393145428079926, "CC210303": 7.673018393542411, "CC210311": 14.576431943872961, "CC210323": 31.081778483525209, "CC210331": 30.067189249720045, "CC210408": 62.738628486108894, "CC210412": 63.94711538461538, "CC210418": 73.721694264987974, "CC210423": 70.039654826897262, "CC210430": 98.045130406889243, "CC210504": 91.969625530436502, "CC210510": 93.321666364934728, "CC210517": 85.521939491083955, "CC210525": 88.782478347768162, "CC210601": 95.859434682964093, "CC210607": 15.974798327739503, "CC210610": 0.0085470085470090006, "CC210614": 0.0, "CC210617": 0.0 }
The toFixed() method only works on floats, it appears you may have a string. You could parse it to a float first.
out.push(key + ': ' + parseFloat(f.properties[key]).toFixed(2));
One-liners are not your friend. JavaScript has its own ideas about priority. To force "order of operation", use parenthesis around any important group. Even then, code editors may format, prettify, or remove the parenthesis. Good luck finding the error then! It is best to isolate any complex operation in a named variable. A named variable is more descriptive and easier to read and reuse.
Seems like the code is calling toFixed on all values, even if the value is a string.
for (key in f.properties) {
//The first few prperties are strings, this is throwing an error as String.prototype.toFixed is not defined, so you can't call it.
out.push(key + ': ' + parseFloat(f.properties[key]).toFixed(2));
parameters += '&' + key.replace(/\ /g, '_') + '=' + f.properties[key];
}
Try this instead
for (var key in f.properties) {//include var to not add key to global scope
var val = f.properties[key]
if (typeof val === "number") {val = val.toFixed(2)}
out.push(key + ': ' + val);
parameters += '&' + key.replace(/\ /g, '_') + '=' + val;
}
Also, as noted in other answers, the values with floates might still be strings, if this is the case, you could try:
for (var key in f.properties) {//include var to not add key to global scope
var val = f.properties[key]
if (Number.isNaN(Number(val))) val = Number(val).toFixed(2)
out.push(key + ': ' + val);
parameters += '&' + key.replace(/\ /g, '_') + '=' + val;
}
You could also use the Array.reduce() method:
var out = Object.keys(f.properties)
.reduce((a, c) => (typeof f.properties[c] === `number` ?
a.push(`${c}: ${f.properties[c].toFixed(2)}`) :
a.push(`${c.replace(/\s/, `_`).toLowerCase()}: ${f.properties[c]}`), a), [])
const f = {
"type": "Feature",
"properties": {
"Row name": "row-1",
"Col": "1",
"plot_num": "?436",
"plot_name": "?AOBS",
"join_key": "?AOBS?436",
"CC201014": 0.0,
"CC201104": 0.0016344676538850001,
"CC201120": 0.56401258728343395,
"CC201217": 8.3524346613304221,
"CC210113": 7.7746312091202094,
"CC210224": 9.7393145428079926,
"CC210303": 7.673018393542411,
"CC210311": 14.576431943872961,
"CC210323": 31.081778483525209,
"CC210331": 30.067189249720045,
"CC210408": 62.738628486108894,
"CC210412": 63.94711538461538,
"CC210418": 73.721694264987974,
"CC210423": 70.039654826897262,
"CC210430": 98.045130406889243,
"CC210504": 91.969625530436502,
"CC210510": 93.321666364934728,
"CC210517": 85.521939491083955,
"CC210525": 88.782478347768162,
"CC210601": 95.859434682964093,
"CC210607": 15.974798327739503,
"CC210610": 0.0085470085470090006,
"CC210614": 0.0,
"CC210617": 0.0
}
};
const urls = [
`/uas_tools/crop_analysis/index.php`,
`/uas_tools/variety_analysis/index.php`
];
const div = document.createElement('div');
Object.keys(f.properties)
.reduce((a, c) => (typeof f.properties[c] === `number` ?
a.push(`${c}: ${f.properties[c].toFixed(2)}`) :
a.push(`${c.replace(/\s/, `_`).toLowerCase()}: ${f.properties[c]}`), a), [])
.map(el => {
const br = document.createElement('br');
const span = document.createElement('span');
span.innerText = el;
div.appendChild(span).appendChild(br);
});
const parameters = {
crop: `Wheat`,
year: 2021,
location: `Amarillo`,
sublocation: `Irrigation`
};
urls.map(pathName => {
const url = new URL(pathName, window.location.origin);
Object.keys(parameters)
.map(elem => url.searchParams.set(elem, parameters[elem]));
const br = document.createElement('br');
const a = document.createElement('a');
a.href = url.toString();
a.target = `_blank`;
a.innerText = url.pathname
.split(`/`)
.slice(-2, -1)[0]
.split(`_`)
.map(el => el.charAt(0).toUpperCase() + el.substr(1).toLowerCase())
.join(` `);
div.appendChild(a).appendChild(br);
});
document.querySelector(`body`).appendChild(div);
body {
font-family: sans-serif;
font-size: 12px;
}
I'm having trouble producing a script to match an object's value in object array based on an object's value in a separate array, and retrieve a separate value from that object.
I have used standard for-loops and the current iteration in jQuery each.
I have also tried setting the if statement to look for the two values as ==, but it always produces non matches (or -1).
Can anyone steer me in the right direction here?
transfers = [
{Package: "1", Origin_Facility = "a"},
{Package: "2", Origin_Facility = "b"}
];
storeData = [
{fromPackage: "1,6,26"}
]
var storeDataEach = function( sx, sxv ) {
var transfersEach = function( sy, syv ) {
if(storeData[sx].fromPackage.indexOf(transfers[sy].Package) > -1){
var facilityStore = transfers[sx].Origin_Facility;
storeData[sx].origin = facilityStore + " + " + transfers[sy].Package + ' + ' + storeData[sx].fromPackage;
return false;
} else {storeData[sx].origin = 'error' + transfers[sy].Package + " + " + storeData[sx].fromPackage;return false;}
};
jQuery.each(transfers, transfersEach);
}
jQuery.each(storeData, storeDataEach);
The main problem is you are returning false from the $.each loop which will stop the iteration
A crude fix is to remove the return from else block
var storeDataEach = function(sx, sxv) {
var transfersEach = function(sy, syv) {
if (storeData[sx].fromPackage.indexOf(transfers[sy].Package) > -1) {
var facilityStore = transfers[sx].Origin_Facility;
storeData[sx].origin = facilityStore + " + " + transfers[sy].Package + ' + ' + storeData[sx].fromPackage;
return false;
} else {
storeData[sx].origin = 'error' + transfers[sy].Package + " + " + storeData[sx].fromPackage;
}
};
jQuery.each(transfers, transfersEach);
}
But this still have problems with the data structure, in your example you have 26 in the fromPackage, now if you have a package value of 2 that also will return a positive result
I have an array and inside each array is a json object with each day of the week, so my array would look something like this:
var array = [
{
"wednesday":{
"notes":"some notes for Wednesday"
},
},
{
"thursday":{
"notes":"some notes for Thursday"
}
}
];
i can get away with updating my object directly by calling the following:
array[0].wednesday.notes = "updating Wednesday notes";
However, I need to update it dynamically....
I have a function that looks something like this, I need to dynamically call the day of the week on my json object and not be locked into just wednesday, i need to be able to call wednesday, thursday, friday etc on my object, how can i do this?
function updateObject(index, empNum) {
console.log(index+", "+empNum)
array[index].employee = $("#employee_" + empNum).val();
array[index].wednesday.notes = $("#employee_" + empNum + "_wed_notes").val();
array[index].wednesday.start = $("#employee_" + empNum + "_wed_shift_start").val();
array[index].wednesday.lunch = $("#employee_" + empNum + "_wed_lunch").val();
array[index].wednesday.end = $("#employee_" + empNum + "_wed_shift_end").val();
array[index].wednesday.short_day = $("#employee_" + empNum + "_wed_short_day").is(':checked');
array[index].wednesday.lack_of_work = $("#employee_" + empNum + "_wed_lack_of_work").is(':checked');
array[index].wednesday.full_day = $("#employee_" + empNum + "_wed_full_day").is(':checked');
var row_count = $("input[id*='employee_" + empNum + "_wed_job_']").length;
for (var i = 0; i < row_count; i++) {
var data = {};
data.job = $("input[id*='employee_" + empNum + "_wed_job_']").eq(i).val();
data.hrs = $("input[id*='employee_" + empNum + "_wed_hrs_']").eq(i).val();
data.cost_code = $("input[id*='employee_" + empNum + "_wed_cost_code_']").eq(i).val();
data.st = $("input[id*='employee_" + empNum + "_wed_st_']").eq(i).is(':checked');
data.ot = $("input[id*='employee_" + empNum + "_wed_ot_']").eq(i).is(':checked');
data.dt = $("input[id*='employee_" + empNum + "_wed_dt_']").eq(i).is(':checked');
array[index].wednesday.data[i] = data;
}
}
i tried something like doing
array[index].[thursday].notes = "x";
but unfortunately that doesnt work, i need to be able to call the day of the week i need when i call the function
so i need it to be something like updateObject(2,1,"thursday");
You just need to use the bracket notation to access the correct element in your array/objects.
This function would let you enter the week number (array index) as well as the day you want to update.
var array = [
{
"wednesday":{
"notes":"some notes for Wednesday"
},
},
{
"thursday":{
"notes":"some notes for Thursday"
}
}
];
function updateArray(index, day, newNotes) {
array[index][day].notes = newNotes;
}
console.log('before', array);
updateArray(1, 'thursday', 'updated notes');
console.log('after', array);
You can access all your data as so:
const updateObject = (index, empNum) => {
const i = array[index], k = Object.keys(i)[0]
if (!k) {return console.error("Invalid Data at index",index)}
i[k].notes = `Whatever you want with ${empNum}`
}
The function isolates the key given at a certain location and accesses it.
Example: updateObject(0, "15 employees")
If you would rather have ^^ do it by day then your function would look like:
const updateObject = (day, empNum) => {
const i = array.map(r => {
const k = Object.keys(r)[0];if (!k) {return false}
return r[k]
}).filter(r => r)[0]
if (!i) {return console.error("Invalid Day [%s] provided",day)}
i.notes = `Whatever you want with ${empNum}`
}
Not you can use it like: updateObject('tuesday', "15 employees")
I seem to have trouble calculating some numbers together. When I want to use:
for (var key in week_total) {
$("." + key).html(week_total[key]);
}
I am getting a NaN and thereforce every group has a NaN. Is this the right way of even using week_total[group] = week_total[group] + work_minutes;?
My script:
drawCallback: function (settings) {
var api = this.api(), data;
var rows = api.rows({page: 'current'}).nodes();
var last = null;
var week_total = new Array;
api.column(weekColumn, { page: 'current' }).data().each(function (group, i) {
var work_hours = api.column(hourColumn).data()[i].split(':');
var work_minutes = (+ work_hours[0]) * 60 + (+ work_hours[1]);
week_total[group] = week_total[group] + work_minutes;
if (last !== group) {
$(rows).eq(i).before('<tr><td colspan="5">{{ trans('admin.worktime.field.week') }} ' + group + '</td><td colspan="3" style="font-style:italic;" class="' + group + '"></td></tr>');
last = group;
}
});
for (var key in week_total) {
$("." + key).html(week_total[key]);
}
var array = {
work_month: work_month,
work_year: work_year
};
history.pushState(null, null, '?' + $.param(array));
drawDataTable(this);
}
I think, problem is in not initialized week_total array.
Calculating should be like
week_total[group] = week_total[group]
? week_total[group] + work_minutes
: work_minutes;
If week_total[group] is undefined then week_total[group] + 1 will be NaN
i have a json object that has item type and id, i need to create new object
var data = {
"items":[
{"type":"generator","id":"item_1","x":200,"y":200},
{"type":"battery","id":"item_2","x":50,"y":300},
{"type":"generator","id":"item_3","x":200,"y":280},
{"type":"battery","id":"item_4","x":100,"y":400}
]
};
and i need to run for each item in items
jQuery.each(data.items, function(index,value) {
eval("var " + value.id + " = new " + value.type + "(" + (index + 1) + ");");
eval(value.id + ".id = '" + value.id + "';");
eval(value.id + ".draw(" + value.x + "," + value.y + ");")
});
this is not a good practice, but what else can i do?
i need then to have the control on the items
something like
item_1.moveto(300,700);
but i always get item_1 is undefind
You can create a factory method which allows to generate concrete types out of an abstract data structure:
var createItem = (function () {
var types = {};
function createItem(index, data) {
data = data || {};
var ctor = types[data.type], item;
if (!ctor) throw new Error("'" + data.type + "' is not a registered item type.");
item = new ctor(index);
item.id = data.id;
return item;
}
createItem.registerType = function (type, ctor) {
types[type] = ctor;
};
return createItem;
})();
Then register item types to the factory:
function Generator(index) {/*...*/}
createItem.registerType('generator', Generator);
And finally create an object map to lookup your items by id (you could use a specialized object like ItemsMap instead of a plain object), loop through your items and add them to the map.
var itemsMap = {};
data.items.forEach(function (itemData, i) {
var item = itemsMap[itemData.id] = createItem(i + 1, itemData);
//you can also draw them at this point
item.draw(itemData.x, itemData.y);
});
You can now lookup objects by id like:
var item1 = itemsMap['item_1'];
var objects = {};
objects[value.id] = new window[value.type](index + 1);