最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Count empty array - Stack Overflow

programmeradmin0浏览0评论

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
  • Wanted to note the reason why this doesn't work is because replacing [ and ] negates an empty array for "[Tom][]" becomes " Tom " then gets trimmed to Tom. Rather than replacing you could for example use str.matchAll(regex) and that tells you the starting and ending positions in the original string. – Spencer Wieczorek Commented Feb 2 at 15:36
Add a comment  | 

8 Answers 8

Reset to default 2

It'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

  1. str.split("[") splits str using [ as the separator into distinct strings that are representing the tokens
  2. .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
  3. .map(item -> item.substring(0, item.length - 1)) takes the token strings, such as tom] and ] into account, gets the substring for them without the closing ] and computes the length of the result, having 3 and 0, respectively instead of the actual tokens
  4. .join(", ") converts the values of this array, 3 and 0 respectively into a single string, separating the items with , so it will result in 3, 0
  1. .split() the given string with this regex:

    /\[(.*?\])/
    

    Result: ["", "Tom]", "", "]", ""]
    Note: the right bracket "]" serves as a placeholder

  2. Next, .reduce() the array by assigning an empty array as the initial value of the accumulator cnt:

    .reduce((cnt, seg) => { ... }, []);
    
  3. Then, skip index of 0 and all even numbered indices:

    if (idx % 2 === 0) return cnt;
    
  4. On any odd numbered index, remove the first character and add the .length of the string to array cnt:

    cnt.push(seg.slice(1).length);
    return cnt;
    

    Result: [3, 0]

  5. 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][]'));

发布评论

评论列表(0)

  1. 暂无评论