I need to count letters of string, I don't know how to count an empty array
const regex = /[\[\]]/gi;
const a = str.replaceAll(regex, ' ').trim().split(" ")
const arr = []
const arr2 = []
let newArr
for(let i = 0; i < a.length; i++) {
if (a[i].length === 0) {
arr2.push(0)
}
if (a[i].length !== 0) {
arr.push(a[i].length)
}
}
newArr = arr.concat(arr2)
if (newArr.includes(0)) {
newArr.pop()
}
return newArr.join(", ")
I must get: [Tom][] -> 3, 0 But I get a 3 without zero
I need to count letters of string, I don't know how to count an empty array
const regex = /[\[\]]/gi;
const a = str.replaceAll(regex, ' ').trim().split(" ")
const arr = []
const arr2 = []
let newArr
for(let i = 0; i < a.length; i++) {
if (a[i].length === 0) {
arr2.push(0)
}
if (a[i].length !== 0) {
arr.push(a[i].length)
}
}
newArr = arr.concat(arr2)
if (newArr.includes(0)) {
newArr.pop()
}
return newArr.join(", ")
I must get: [Tom][] -> 3, 0 But I get a 3 without zero
Share Improve this question edited Feb 2 at 20:49 Daksh Rawal 5705 silver badges20 bronze badges asked Feb 2 at 15:10 DerekDerek 553 bronze badges 1 |8 Answers
Reset to default 2It's not described in the question text, but according to your code, the input string has the format: (\[[a-zA-Z]*\])*
.
I would remove the first [
and the last ]
. Then, I would split the string by ][
.
const str = '[Tom][]';
const substrs = str.substring(1, str.length - 1).split('][');
const lengths = substrs.map(str => str.length);
console.log(lengths.join(', '));
using es6 you can do it in more simpler way
const str = '[Tom][]';
const count = str.match(/\[(.*?)\]/g)
.map(x => x.slice(1, -1))
.map(x => x.length)
.join(', ');
console.log(count);
You can achieve that with array operations:
function f(str) {
return str.split("[").filter(item => item.length).map(item => item.substring(0, item.length - 1).length).join(", ");
}
console.log(f("[tom][]"));
Explanation
str.split("[")
splitsstr
using[
as the separator into distinct strings that are representing the tokens.filter(item => item.length)
on the array we've got in the previous step will ignore any tokens that we empty strings, in this case the first item of the split is empty string, because that's the 0'th token and we want to ignore it.map(item -> item.substring(0, item.length - 1))
takes the token strings, such astom]
and]
into account, gets the substring for them without the closing]
and computes thelength
of the result, having 3 and 0, respectively instead of the actual tokens.join(", ")
converts the values of this array, 3 and 0 respectively into a single string, separating the items with,
so it will result in3, 0
.split()
the given string with this regex:/\[(.*?\])/
Result:
["", "Tom]", "", "]", ""]
Note: the right bracket"]"
serves as a placeholderNext,
.reduce()
the array by assigning an empty array as the initial value of the accumulatorcnt
:.reduce((cnt, seg) => { ... }, []);
Then, skip index of 0 and all even numbered indices:
if (idx % 2 === 0) return cnt;
On any odd numbered index, remove the first character and add the
.length
of the string to arraycnt
:cnt.push(seg.slice(1).length); return cnt;
Result:
[3, 0]
Finally,
.join(", ")
the array of numbers into a string.
const charCounts = (str) => {
return str
.split(/\[(.*?\])/)
.reduce((cnt, seg) => {
if (idx % 2 === 0) return cnt;
cnt.push(seg.slice(1).length);
return cnt;
}, []).join(", ");
};
console.log(charCounts("[Tom][]"));
Use String.matchAll()
to find all capture groups that are between []
, and don't contain ]
. Convert the iterator to an array of entries using Array.from()
, and take the length from the 2nd item of entry:
const str = '[Tom][]';
const count = Array.from(str.matchAll(/\[([^\]]*)\]/g), ([, s]) => s.length)
.join(', ')
console.log(count);
Here's a super simple example that uses RegExp with Positive Lookbehind:
const str = "[Tom][][Anna][][][John]";
const arr = str.match(/(?<=\[)[^\]]*/g);
console.log(arr); // ["Tom", "", "Anna", "", "", "John"]
console.log(arr.map(s => s.length)); // [3, 0, 4, 0, 0, 4]
Demo and explanation on: Regex101
The issue is around the trim
that removes the white spaces regardless of the number of white spaces. You need to split your result with " "
so you find the empty arrays.
const myFunc = str => str.replaceAll( /[[\]]/gi, " ")
.split(" ")
.map(v => v.trim().length)
.join(", ");
console.log(myFunc("[Tom][]"));
console.log(myFunc("[Tom Jobim][]"));
However, it is not a good practice to use white spaces as separator: it can be an issue if in an input array you have two following white spaces. A better approach is to replace white spaces in your original input string (str
), and replace them back before get the length of the names. The replacement string must not be a substring of the original str
Bug-free version
const myFunc = str => {
let replacer = "¤"
while(str.indexOf(replacer) >=0) replacer += "¤"
let tmp_str = str.replaceAll(" ",replacer)
return tmp_str.replaceAll( /[[\]]/gi, " ")
.split(" ")
.map(v => v.replaceAll(replacer, " ").trim().length)
.join(", ");
}
console.log(myFunc("[Tom][]"));
console.log(myFunc("[Tom Jobim][]"));
You could use a JSON string and with previous replacements and take the lengths after parsing.
const
count = s => JSON
.parse(`[${s
.replaceAll('][', '],[')
.replaceAll(/\[|\]/g, '"')}]`)
.map(s => s.length);
console.log(count('[Tom][]'));
[
and]
negates an empty array for"[Tom][]"
becomes" Tom "
then gets trimmed toTom
. Rather than replacing you could for example usestr.matchAll(regex)
and that tells you the starting and ending positions in the original string. – Spencer Wieczorek Commented Feb 2 at 15:36