This question already has answers here:
Dynamic regex pattern in JavaScript
(4 answers)
Closed 2 years ago.
I have a response and it returns "XXX-XXX" or "XX-XXXX"
const formatUnitCode = (value, format) => {}
So basically, I want to see as formatUnitCode("123456", "XX-XXX") --> "12-3456"
I don't want to use if else because it may come in the future as XX-XX-XX
Can someone help me create this function?
I tried to do with regex but I think it is not possible to pass variable instead of {2} and {4}
const formatCode = (val) => val.replace(/(\d{2})(\d{4})/g, "$1-$2");
Is this what you would like to do?
const func = (val, first_digit) => {
let regex = new RegExp("(\\d{" + first_digit + "})(\\d{" + (6-first_digit) + "})","g");
return val.replace(regex,"$1-$2");
};
You can use simple for loop make a dynamic string format method.
const formatUnitCode = (str, format) => {
let result = '';
let j = 0;
for (let i = 0, l = format.length; i < l; i += 1) {
if (format[i] === 'X') {
result += str[j];
j += 1;
} else result += format[i];
}
for (; j < str.length; j += 1) result += str[j];
return result;
};
console.log(formatUnitCode('123456', 'XX-XXX'));
console.log(formatUnitCode('123456', 'XXX-XXX'));
console.log(formatUnitCode('123456', 'XX-XXXX'));
console.log(formatUnitCode('123456', 'XX-XX-XX'));
You can't use variables in RegExp literals, but you can when you use the RegExp() constructor to build the pattern as a string instead.
const formatStr = (val, format) => {
let ptn = format.split('-').map(part => '(.{'+part.length+'})').join('');
match = val.match(new RegExp(ptn));
match && console.log(match.slice(1).join('-'));
};
It's instructive to console.log() the ptn var to see what's happening there. We're using your arbitrary "X"-based format to derive a new, dynamic RegExp which will be used in a multi-match RegExp to grab the parts.
formatStr('123456', 'xxx-xxx'); //"123-456"
formatStr('123456', 'xx-xxxx'); //"12-3456"
This should work for any mask regardless of the letters used (you can control that behaviour by changing matcher regex). Personally, I think it's a more elastic approach than just trying to match the given mask with a regex.
const replaceWithFiller = (filler, str, matcher = /[a-zA-z]/g) => {
const arr = filler.split('');
return str.replace(matcher, () => arr.shift());
};
console.log(replaceWithFiller('123456', 'XXX-XXX')); //"123-456"
console.log(replaceWithFiller('123456', 'XX-XX-XX')); // "12-34-56"
console.log(replaceWithFiller('123456', 'XX-XXXX')); //"12-3456"
console.log(replaceWithFiller('123456', 'aa-aaaa')); // also "12-3456"
you can pass parameters to your regex using template literals:
const formatCode = (val, format) => {
const lengthFirstBlock = format.indexOf('-');
const lehgthSecondBlock = format.length - format.indexOf('-');
const regex = new RegExp(`(\\d{${lengthFirstBlock}})(\\d{${lehgthSecondBlock}})`, 'g');
return val.replace(regex, "$1-$2");
}
console.log(formatCode("123456", "XX-XXX"))
console.log(formatCode("123456", "XXX-XX"))
I've already did this using a loop but our instructor said that it can be done with a shorter and simpler method/function. We are not allowed to use for loops or foreach. We can only use es6 related code.
This is my code.
var total = 0
let givenWord = "cabbage"
let pointsTable = new Map([['a',1],['e',1],['i',1],['o',1],['u',1],['l',1],['n',1],['r',1],['s',1],['t',1],
['d',2],['g',2],['b',3],['c',3],['m',3],['p',3],['f',4],['h',4],['v',4],['y',4],['k',5],['j',8],['x',8],['q',10],['z',10]])
for(let [...letters] of givenWord){
for(let [key,value] of pointsTable){
if(letters == key){
total = total + value;
console.log("Total value is " + total)
}
}
}
my problem here is that my loops take up too many lines of code. How do I transform this one into simpler code or using a function/method ? using only ES6?
Ok, I created a sort ES6 way to return the chars in an array and run a check function on them:
const pointsTable = new Map([['a',1],['e',1],['i',1],['o',1],['u',1],['l',1],['n',1],['r',1],['s',1],['t',1],
['d',2],['g',2],['b',3],['c',3],['m',3],['p',3],['f',4],['h',4],['v',4],['y',4],['k',5],['j',8],['x',8],['q',10],['z',10]])
// With ES6
const text= 'abcdefg';
const result = [...text].reduce((acc, cur) => {
return acc + pointsTable.get(cur)
}, 0);
console.log(result);
An other way you could do this is write a while loop and use the String.split(), String.slice() or String.substring() methods to reduce the string to the chars
You can use recursion for this task:
var total = 0
let givenWord = "cabbage"
let pointsTable = new Map([['a',1],['e',1],['i',1],['o',1],['u',1],['l',1],['n',1],['r',1],['s',1],['t',1],
['d',2],['g',2],['b',3],['c',3],['m',3],['p',3],['f',4],['h',4],['v',4],['y',4],['k',5],['j',8],['x',8],['q',10],['z',10]])
const countTotal = (arr, map, points = 0) => {
if(arr.length === 0) return points
points += map.get(arr.splice(0,1)[0])
return countTotal(arr, map, points)
}
console.log(countTotal([...givenWord],pointsTable))
Using the split method it will separate the text into the individual letters. Then you can use the map method to iterate through each of those letters and do a check within that.
const test = 'abcdefg'
let total = 0;
let pointsTable = new Map([['a',1],['e',1],['i',1],['o',1],['u',1],['l',1],
['n',1],['r',1],['s',1],['t',1],
['d',2],['g',2],['b',3],['c',3],['m',3],['p',3],['f',4],['h',4],['v',4],
['y',4],['k',5],['j',8],['x',8],['q',10],['z',10]])
test.split('').map(function(letter){
let value = pointsTable.get(letter)
total += value;
});
Here's the shortest way I can think of :
var total = 0
let givenWord = "cabbage"
let pointsTable = new Map([['a',1],['e',1],['i',1],['o',1],['u',1],['l',1],['n',1],['r',1],['s',1],['t',1],
['d',2],['g',2],['b',3],['c',3],['m',3],['p',3],['f',4],['h',4],['v',4],['y',4],['k',5],['j',8],['x',8],['q',10],['z',10]])
let total = givenWord.split``.reduce((a,l)=>a+pointsTable.get(l),0)
console.log("Total value is " + total)
details :
let total = // assign to total
givenWord // the givenword
.split`` // splited to get an array of characters
.reduce( // call reduce on the array
(a, l) => { // first arg of reduce is a function
// called for each elements of the array
// arguments are the accumulator, the letter
a + pointsTable.get(l) // add the letter score to the accumulator
},
0 // set default value of accumulator (2nd arg of reduce)
)
fn`` documentation (look at section tagged template),
reduce documentation
This Works:
setTheme('#222','#000','wheat','red','wheat','none','none');
This does not work:=
var theme01 = "'#222','#000','wheat','red','wheat','none','none'"; <br>
setTheme(theme01);
console.log(theme01) = '#222','#000','wheat','red','wheat','none','none'
So the conversion to string messes it up somehow?
I will be toggling through various themes before capturing the canvas? I had it all working with CSS, but canvas does not capture css changes or css injection. So I now have it all ready to go using Vanilla Javascript, but need help after hours of testing searching just to pass a variable to my function. Grrr. Help!
I have only been at this for a couple of weeks, so it's a learning curve after working only in Wordpress.
function setTheme(topp,bott,txt,hlin,vlin,fOrb,sOrb) {
var xx = document.querySelectorAll(".hlin");
for (var i = 0; i < xx.length; i++) {
xx[i].style.stroke = hlin;
}
var xx = document.querySelectorAll(".vlin");
for (var i = 0; i < xx.length; i++) {
xx[i].style.stroke = vlin;
}
var xx = document.querySelectorAll(".txt");
for (var i = 0; i < xx.length; i++) {
xx[i].style.fill = txt;
}
document.getElementById("svg_20").style.fill = topp;
document.getElementById("svg_1").style.fill = bott;
document.getElementById("svg_2").style.fill = bott;
document.getElementById("svg_3").style.stroke = txt;
document.getElementById("svg_5").style.stroke = txt;
document.getElementById("svg_21").style.fill = fOrb;
document.getElementById("svg_21").style.stroke = sOrb;
};
Yep, you can’t exchange a list of parameters for a comma-separated string. You should use a data structure to store them, like an array or object. Here’s an example of how it would work with an object.
var theme01 = { topp: '#222', bott: '#000', txt: 'wheat' };
function setTheme ( options ) {
document.getElementById("svg_20").style.fill = options.topp;
document.getElementById("svg_1").style.fill = options.bott;
document.getElementById("svg_3").style.fill = options.txt;
}
setTheme( theme01 )
The string will be one parameter for your function. You can use Function.apply )1 with a splitted string as second parameter, or even simpler, use the spread operator 2). Demo:
1) Function.apply
2) spread operator
( () => {
const log = str => document.querySelector("#result").textContent += `${str} \n`;
const parameterString = "#222,#000,wheat";
// no dice
log("someFn(parameterString) => no dice");
someFn(parameterString);
// use apply
log("\nsomeFn.apply(null, parameterString.split(\",\")) => ah yes, that works");
someFn.apply(null, parameterString.split(","));
// or use spread operator
log("\nsomeFn(...parameterString.split(\",\")) => ah yes, that works too");
someFn(...parameterString.split(","));
function someFn(p1, p2, p3) {
log(p1);
log(p2);
log(p3);
}
})();
<pre id="result"></pre>
You can pass it as an array using spread syntax, you cannot however pass a string of items and have them be multiple parameters.
function setTheme(topp, bott, txt, hlin, vlin, fOrb, sOrb) {
console.log(topp)
console.log(bott)
console.log(txt)
console.log(hlin)
console.log(vlin)
console.log(fOrb)
console.log(sOrb)
}
let items = ['#222', '#000', 'wheat', 'red', 'wheat', 'none', 'none']
setTheme(...items)
I use a react component which work like this
<FontAwesomeIcon icon={faCoffee} />
it take a font awesome icon let say address-book it add fa before, delete hyphen and uppercase the first letter of each world.
address-book become faAddressBook
copyright become faCopyright
arrow-alt-circle-down become faArrowAltCircleDown
Is it possible to create a javascript function which take an array like this
["address-book","copyright","arrow-alt-circle-down"]
and transform it in an array like that
["faAddressBook","faCopyright","faArrowAltCircleDown"]
There are some ways to do it. Like using regular expression. However, your requirement is simple, so it can be easily done with JavaScript split method. Please check the following implemented function.
function formatArray(str)
{
str = str.split("-");
for (var i = 0, x = str.length; i < x; i++) {
str[i] = str[i][0].toUpperCase() + str[i].substr(1);
}
return 'fa' + str.join("");
}
var givenArr = ["address-book","copyright","arrow-alt-circle-down"];
for( var i = 0; i < givenArr.length; i++) {
givenArr[i] = formatArray(givenArr[i]);
console.log(givenArr[i]+ '\n');
}
You can do the following with Array's map() and forEach():
var arr = ["address-book","copyright","arrow-alt-circle-down"];
function upperCase(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
var outPut = arr.map(function(item){
var temp = item.split('-');
var temp2 = [];
temp.forEach(function(data){
temp2.push(upperCase(data))
});
return 'fa' + temp2.join('')
})
console.log(outPut);
Looks like there's two essential steps here. First, we need to prepend fa onto each string, and second, we need to convert them from kebab-case to camelCase.
So just write a function for each of those conversions, then run your array through a map using each of them:
const kebabs = ["address-book","copyright","arrow-alt-circle-down"];
function kebabToCamel(str) {
return str.replace(/-(\w)/g, m => m[1].toUpperCase());
}
function prependFa(str) {
return "fa-" + str;
}
console.log(kebabs.map(prependFa).map(kebabToCamel))