use str.split() on every second occurrence of our delimiter - javascript

I have a series of varying strings which I need to turn into arrays on every second occurrence of \n, for simplicity please consider the next example:
const str = 'banana\napple\nmango\n3.5'
//I have tried and failed with:
const arr = str.split(/(^\n)+\n(^\n)+/)
// Result should be:
// const arr = ['banana\napple', 'mango\n3.5']
Do I have to use a loop here or what?

You could take match instead of split by taking some non breaking character, a breaking character and other non breking character.
const
string = 'banana\napple\nmango\n3.5',
result = string.match(/[^\n]+\n[^\n]+/g);
console.log(result);

Damn this is an ugly approach:
let t1 = performance.now();
const result = 'banana\napple\nmango\n3.5'
.split('\n')
.map((str, i, arr) => (i % 2) === 0 ? str + '\n' + arr[i+1] : null )
.filter((str) => str !== null);
let t2 = performance.now();
console.log(result, t2-t1 + 'μs');

Related

JavaScript: How can I split a decimal number into 2 part according to where the first zero occurs after a non-zero integer

Sorry if the title sounds confusing. Basically what I am trying to do is to split a decimal number like this 0.1000 into two part - 1. 0.1 and 000 so I can render them differently with different styles.
Check out this screenshot
All the numbers are represented in strings. The tricky part is that we cannot split the number using number.split('0') since we only want to split at the first zero that appears after a non-zero integer.
Not sure how I can do this.
If I did not misunderstand what you are trying to achieve, you can do it with a regex that only matches unlimited zeros that are at the end of the given string like follows:
function markNumber(num) {
return num.replace( /(0{1,})$/g, '<span>$1</span>')
}
const number = 1.2345670089
let renderStyle1 = ''
let renderStyle2 = ''
const string = String(number) + '.'
const parts = string.split('.')
const decimals = parts[1]
const decimalsArray = Array.from(decimals);
// From MDN: The findIndex() method returns the index of the first element in the array that satisfies the provided testing function. Otherwise -1 is returned.
const firstIndexOfZero = decimalsArray.findIndex(x => x === '0');
// From MDN: The slice() method returns a shallow copy of a portion of an array into a new array object selected from start to end (end not included) where start and end represent the index of items in that array. The original array will not be modified.
if(firstIndexOfZero === -1){
renderStyle1 = parts[0] + parts[1]
} else {
renderStyle1 = parts[0] + decimalsArray.slice(0, firstIndexOfZero).join('') // using .join method to convert array to string without commas
renderStyle2 = decimalsArray.slice(firstIndexOfZero, decimalsArray.length).join('') // using .join method to convert array to string without commas
}
console.log(renderStyle1) // "1234567"
console.log(renderStyle2) // "0089"
Messy, and, probably, can be improved, but this should work:
let re = /(\d*\.[1-9]*?)(0.*)/;
["1000", "1.01", "1.10", "1.000", "1.34043"].map((str) =>
str.split(re).filter((entry) => entry !== "")
);
Here's my regex function
const number = ['0.1000', '2.534300', '1.2000', '1.004334000'];
function split_float(num) {
const reg = /^(\d*\.\d*[^0])(0*)$/g;
const [, ...matches] = [...num.matchAll(reg)][0];
return matches;
}
console.log(number.map(split_float));
here is my answer. It uses split and substring to achieve what you want. Tried it in w3school's tryit editor. Handles all of your data in screenshot pretty well:
function myFunction() {
var str = "0.01200";
var partone = str.split(".")[0];
var temp = str.split(".")[1];
for (var i=0; i<temp.length; i++){
if (temp[i] != 0 && temp[i+1] == 0){
break;
}
}
var parttwo = temp.substring(i+1);
partone = partone + "." + temp.substring(0, i+1);
var res = "partOne = " + partone + " and partTwo = " + parttwo;
document.getElementById("demo").innerHTML = res;
}
Here is the screenshot:

Adding numeric values in a string together

I have a string returned from an endpoint in which I need to add certain parts of the string together in order to produce two different values.
Example response:
149,226;147,226;146,224
Now I know I can use the unary plus operator to force the string to be treated as a number like so.
var num1 = '20',
num2 = '22';
var total = (+num1) + (+num2);
or I could do some conversion like so
var number1 = parseInt(num1);
var number2 = parseInt(num2);
var total = number1 + number2;
either of these work fine however this is not what I am looking for exactly.
I want to take this result
149,226;147,226;146,224
Then add all the numbers before the first comer together so that would be (149, 147, 146) to produce one result and then add all the number after the second comer together (226, 226, 224).
I know I probably need some sort of reg expression for this I just dont know what.
You can just use string.split, twice, one for the ; and then again for the ,. And put this through array.reduce.
eg.
var str = '149,226;147,226;146,224';
var result = str.split(';')
.reduce((a,v) => {
var vv = v.split(',');
a[0] += vv[0] | 0;
a[1] += vv[1] | 0;
return a;
}, [0, 0]);
console.log(result);
For a more generic solution, that could handle any number of sub strings, eg. 1,2,3;4,5,6, and also handle alternative split types, and cope with extra , or ;.
function sumStrings(str, outerSplit, innerSplit) {
return str.split(outerSplit || ';')
.filter(Boolean)
.reduce((a,v) => {
v.split(innerSplit || ',')
.filter(Boolean)
.forEach((v,ix) => {
a[ix] = (a[ix] | 0) + (v | 0);
});
return a;
}, []);
}
console.log(sumStrings(
'149,226;147,226;146,224'
));
console.log(sumStrings(
'149.226.201|147.226.112.|146.224.300|',
'|','.'));
//how about total of totals?
console.log(sumStrings(
'149,226;147,226;146,224'
).reduce((a,v) => a + v));
.as-console-wrapper {
min-height: 100%
}
You could do:
const myString = '149,226;147,226;146,224';
/*
* 1. you split the string by ';' to obtain an array of string couples
* then you split each couple by ','. In this way you end up with an array like this:
* [['149', '266'], ['147', '266'], ['146', '264']]
*/
const myNumbers = myString.split(';').map(numCouple => numCouple.split(','));
/*
* 2. you use Array.prototype.reduce() to calculate the sums
*/
const sum1 = myNumbers.reduce((sum, item) => {
return sum += parseInt(item[0]);
}, 0);
const sum2 = myNumbers.reduce((sum, item) => {
return sum += parseInt(item[1]);
}, 0);
// or, as an alternative:
const sumsObj = myNumbers.reduce((obj, item) => {
obj.sum1 += parseInt(item[0]);
obj.sum2 += parseInt(item[1]);
return obj;
}, { sum1: 0, sum2: 0 });
// or also:
const sumsArr = myNumbers.reduce((acc, item) => {
acc[0] += parseInt(item[0]);
acc[1] += parseInt(item[1]);
return acc;
}, [0, 0]);
// test
console.log('sum1:', sum1);
console.log('sum2:', sum2);
console.log('--------------');
console.log('sum1:', sumsObj.sum1);
console.log('sum2:', sumsObj.sum2);
console.log('--------------');
console.log('sum1:', sumsArr[0]);
console.log('sum2:', sumsArr[1]);
without using regex, one possible solution:
var c = '149,226;147,226;146,224'
var d = c.split(";")
var first = d.map(x=>Number(x.split(",")[0]))
var second= d.map(x=>Number(x.split(",")[1]))
console.log(first)
console.log(second)
let resultFirst = first.reduce((a,b) => a + b, 0);
let resultSecond = second.reduce((a,b) => a + b, 0);
console.log(resultFirst)
console.log(resultSecond)
Below supplies regex to String's .split to get the numbers by themselves. Then you could add every other number but I don't see why not just add them all in order.
const str = '149,226;147,226;146,224'
const total = str.split(/[;,]/).map(Number).reduce((a, b) => a + b)
console.log('total', total)
I got this one running:
const nums = ('149,226;147,226;146,224');
var firstNums = nums.match(/(?<=[0-9]*)[0-9]+(?=,)/gs);
var secondNums = nums.match(/(?<=[0-9]*)[0-9]+(?=;|$)/gs);
console.log(firstNums, secondNums);
let sumFirstNums = 0,
sumSecondNums = 0;
firstNums.map(x => {
sumFirstNums += +x;
})
console.log(sumFirstNums)
secondNums.map(x => {
sumSecondNums += +x;
})
console.log(sumSecondNums)
//If you want the result in the same format:
const finalResult = `${sumFirstNums}, ${sumSecondNums};`
console.log(finalResult)
;)
For that string format, you could use a single pattern with 2 capturing groups matching 1+ more digits between a comma, and asserting a ; or the end of the string at the right.
You refer to the group values by indexing into the match of every iteration.
(\d+),(\d+)(?=;|$)
The pattern matches
(\d+) Capture group 1, match 1+ digits
, Match a comma
(\d+) Capture group 2, match 1+ digits
(?=;|$) Positive lookahead, assert directly to the right a ; or end of the string
See a regex demo.
let result1 = 0;
let result2 = 0
for (const match of "149,226;147,226;146,224".matchAll(/(\d+),(\d+)(?=;|$)/g)) {
result1 += +match[1]
result2 += +match[2]
}
console.log(result1, result2);

Formatting array elements into Uppercase and lower case format using JavaScript

I have an array of strings. I need to display those elements into proper format. Like this example.
let array1 = ["WORLDWIDE_AGRICULTURAL - CA"," WORLDWIDE_INDUSTRIAL - MX"]
I have to display it like below:
let formattedArray = ["Worldwide Agricultural - CA","Worldwide Industrial - MX"]
There are multiple of elements so I have to save formatted strings into array. I have tried but it is not coming properly.
Any help is much appreciated.
if(array1.indexOf("WORLDWIDE_AGRICULTURAL")>=0 || array1.indexOf(" WORLDWIDE_INDUSTRIAL") >=0){ var locname1 = array1.split('-'); var locname2 =locname1[0].trim(); var locname3 = locaname1[1].trim(); var formattedArray = locname2.toUpperCase()+ ' - '+locname3.toUpeerCase();
But, it is coming in uppercase and i have to all formatted elements into array.
You could use .map() with .replace() and the replacement method to convert your capital groups into lowercase groups like so:
const array1 = ["WORLDWIDE_AGRICULTURAL - CA"," WORLDWIDE_INDUSTRIAL - MX"];
const res = array1.map(str =>
str.replace(/(\w)(\w+)_(\w)(\w+)/g, (_, a, b, c, d) =>
`${a}${b.toLowerCase()} ${c}${d.toLowerCase()}`
).trim()
);
console.log(res);
The expression first matchs the first character in the string and groups that in group a. It then groups the remaining characters in group b up until the underscore. Then, it groups the first character after the underscore (group c). Lastly, it groups the remaining characters up to the next space. Using the replacement method, we can change group b to lowercase, and group d to lowercase, giving you a capitalized string.
An alternate approach which would require less grouping is to extract the first character from the first and second group, and capitalize the rest:
const array1 = ["WORLDWIDE_AGRICULTURAL - CA"," WORLDWIDE_INDUSTRIAL - MX"];
const res = array1.map(str =>
str.replace(/(\w+)_(\w+)/g, (_, [a, ...b], [c, ...d]) =>
`${a}${b.join('').toLowerCase()} ${c}${d.join('').toLowerCase()}`
).trim()
);
console.log(res);
let array1 = ["WORLDWIDE_AGRICULTURAL - CA", " WORLDWIDE_INDUSTRIAL - MX"];
function titleCase(str) {
var splitStr = str.toLowerCase().split(' ');
for (var i = 0; i < splitStr.length; i++) {
if (splitStr[i].length > 2) {
splitStr[i] = splitStr[i].charAt(0).toUpperCase() + splitStr[i].substring(1);
} else {
splitStr[i] = splitStr[i].toUpperCase()
}
}
return splitStr.join(' ');
}
const formattedArray = array1.map((x) => titleCase(x));
console.log(formattedArray);
Here's what would match your current demonstrated requirement:
let array1 = ["WORLDWIDE_AGRICULTURAL - CA"," WORLDWIDE_INDUSTRIAL - MX"]
function formatter(str) {
let split = str.split("-")
let formattedFirst = split[0].replace(/_/g, " ")
.replace(/\w\S*/g, function(txt) {
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
});
return `${formattedFirst} - ${split[1]}`
}
let convertedArray = array1.map(formatter)
console.log(convertedArray);
First, it seems like you only want to format whats before the ' - ' so we split on that. Then using replace we turn the _ into ' ' after which we can convert to title casing by capitalizing the first letter and lower casing the rest. Afterwards, we recombine to restore the original format of the rest of the string

Replace every nth character equal to "x"

I have a string where common characters are repeated.
For example
x1234,x2345,x3456,x4567,x5678,x6789
I'm trying to replace every nth occurrence of the character "x" starting from the first occurrence with the character "d" using javascript.
The final output should be as follows
d1234,x2345,d3456,x4567,d5678,x6789
You could add a counter and replace by using a remainder for checking.
function replace(string, char, repl, n) {
var i = 0;
return string.replace(new RegExp(char, 'g'), c => i++ % n ? c : repl);
}
console.log(replace('x1234,x2345,x3456,x4567,x5678,x6789', 'x', 'd', 2));
console.log(replace('x1234,x2345,x3456,x4567,x5678,x6789', 'x', 'd', 3));
function replaceNth(str, n, newChar) {
const arr = str.split(',');
return arr.map((item, i) => (i % n === 0) ? item.replace('x', newChar) : item).join(",")
}
const str = 'x1234,x2345,x3456,x4567,x5678,x6789';
// replace for every second string value
console.log(
replaceNth(str, 2, 'd')
);
// replace for every third string value
console.log(
replaceNth(str, 3, 'e')
);
var splittedWords = "x1234,x2345,x3456,x4567,x5678,x6789".split(",")
var result = splittedWords.map((element, index) => index % 2 ? element : "d" + element.substring(1))
console.log(result.join(","))
Can use a regular expression to match a pattern
var str1 = "x1234,x2345,x3456,x4567,x5678,x6789"
var result1 = str1.replace( /x([^x]+(x|$))/g, 'd$1')
console.log(result1)
var str2 = "x1234,x2345,x3456"
var result2 = str2.replace( /x([^x]+(x|$))/g, 'd$1')
console.log(result2)
Explanation of reg exp: RegExper
or can just do a simple split, map, join
var str = "x1234,x2345,x3456,x4567,x5678,x6789"
var result = str.split(",") // split on comma
.map((part,index) => // loop over array
index % 2 === 0 // see if we are even or odd
? "d" + part.substring(1) // if even, remove first character, replace with 1
: part) // if odd, leave it
.join(",") // join it back together
console.log(result)
This assumes that the x is always after the comma, which may or may not be true. If not, then the logic needs to be more complicated.

Javascript: How can I loop through a word and slice off the characters after the first vowel?

I am trying to make a function that loops through a word, identifies the first vowel found (if any) in the word, and then splits up the word after the vowel.
example input: 'super'
example output: 'su', 'per'
function consAy(word){
if(word[i].indexOf("a" >= 0) || word[i].indexOf("e" >= 0) || word[i].indexOf("i" >= 0) || word[i].indexOf("o" >= 0) || word[i].indexOf("u" >= 0)){
}
One way to do it is to use a regular expression to .match() the pattern you are looking for:
function consAy(word){
var result = word.match(/^([^aeiou]*[aeiou])(.+)$/i)
return result ? result.slice(1) : [word]
}
console.log( consAy('super') )
console.log( consAy('AMAZING') )
console.log( consAy('hi') )
console.log( consAy('why') )
The function I've shown returns an array. If there was a vowel that was not at the end then the array has two elements. If there was only a vowel at the end, or no vowel, then the array has one element that is the same as the input string.
A brief breakdown of the regex /^([^aeiou]*[aeiou])(.+)$/i:
^ // beginning of string
[^aeiou]* // match zero or more non-vowels
[aeiou] // match any vowel
.+ // match one or more of any character
$ // end of string
...where the parentheses are used to create capturing groups for the two parts of the string we want to separate, and the i after the / makes it case insensitive.
The .match() method returns null if there was no match, so that's what the ternary ?: expression is for. You can tweak that part if you want a different return value for the case where there was no match.
EDIT: I was asked for a non-regex solution. Here's one:
function consAy(word){
// loop from first to second-last character - don't bother testing the last
// character, because even if it's a vowel there are no letters after it
for (var i = 0; i < word.length - 1; i++) {
if ('aeiou'.indexOf(word[i].toLowerCase()) != -1) {
return [word.slice(0, i + 1), word.slice(i + 1)]
}
}
return [word]
}
console.log( consAy('super') )
console.log( consAy('AMAZING') )
console.log( consAy('hi') )
console.log( consAy('why') )
This assumes a reasonably modern browser, or Node.
const string = "FGHIJK";
const isVowel = c => c.match(/[AEIOU]/i);
const pos = [...string].findIndex(isVowel);
const truncatedString = `${[...string].slice(0, pos + 1)}`;
truncatedString; // "FGHI"
Edit
As has been pointed out, the above is significantly more hassle than it's worth. Without further ado, a much saner approach.
const string = "FGHIJK";
const vowels = /[aeiou]/i;
const truncateAfter = (string, marker) => {
const pos = string.search(marker);
const inString = pos >= 0;
return string.slice(0, inString ? pos : string.length);
};
const truncated = truncateAfter(string, vowels);
Without using a RegEx of any kind. Ye ole fashioned algorithm.
const truncateAfter = (string, markers) => {
let c = "";
let buffer = "";
for (let i = 0, l = string.length; i < l; i += 1) {
c = string[i];
buffer += c;
if (markers.includes(c)) {
break;
}
}
return buffer;
};
const truncatedString = truncateAfter(
"XYZABC",
["A", "E", "I", "O", "U"],
);
With RegEx golf.
const string = "BCDEFG";
const truncatedString = string.replace(/([aeiou]).*/i, "$1");
With a reduction.
const isVowel = c => /[aeiou]/i.test(c);
const last = str => str[str.length - 1];
const truncatedString = [...string].reduce((buffer, c) =>
isVowel(last(buffer)) ? buffer : buffer + c, "");
Via a dirty filter hack, that takes way too much power O(n**2).
const truncatedString = [...string]
.filter((_, i, arr) => i <= arr.search(/[aeiou]/i));
There are others, but I think that's enough to shake the cobwebs out of my brain, for now.
I always like to take opportunities to write incomprehensible array-based code, so with that in mind...
const regexMatcher = pattern => input => {
return input.match(pattern)
};
const splitAtFirstMatch = matcher => arrayLike => {
return [...arrayLike]
.reduce(([pre, post, matchFound], element) => {
const addPre = matchFound || matcher(element);
return [
matchFound ? pre :[...pre, element],
matchFound ? [...post, element] : post,
addPre
];
}, [[],[], false])
.slice(0, 2)
.map(resultArrays => resultArrays.join(''));
};
console.log(splitAtFirstMatch(regexMatcher(/[aeiou]/))('super'));

Categories