28

I've found this beautiful method for removing empty strings - arr = arr.filter(Boolean).

But it doesn't seem to work on whitespace strings.

var arr = ['Apple', '  ', 'Mango', '', 'Banana', ' ', 'Strawberry'];
arr = arr.filter(Boolean);
// ["Apple", "  ", "Mango", "Banana", " ", "Strawberry"]

// should be ["Apple", "Mango", "Banana", "Strawberry"]

Is there a nice way to expand this method to removing whitespaces as well or should i trim the whitespaces by iterating the array first?

Community
  • 1
  • 1
Daniel
  • 6,194
  • 7
  • 33
  • 59

9 Answers9

65

filter works, but you need the right predicate function, which Boolean isn't (for this purpose):

// Example 1 - Using String#trim (added in ES2015, needs polyfilling in outdated
// environments like IE)
arr = arr.filter(function(entry) { return entry.trim() != ''; });

or

// Example 2 - Using a regular expression instead of String#trim
arr = arr.filter(function(entry) { return /\S/.test(entry); });

(\S means "a non-whitespace character," so /\S/.test(...) checks if a string contains at least one non-whitespace char.)

or (perhaps a bit overboard and harder to read)

// Example 3
var rex = /\S/;
arr = arr.filter(rex.test.bind(rex));

With an ES2015 (aka ES6) arrow function, that's even more concise:

// Example 4
arr = arr.filter(entry => entry.trim() != '');

or

// Example 5
arr = arr.filter(entry => /\S/.test(entry));

Live Examples -- The ES5 and earlier ones:

var arr = ['Apple', '  ', 'Mango', '', 'Banana', ' ', 'Strawberry'];
console.log("Example 1: " + JSON.stringify(arr.filter(function(entry) { return entry.trim() != ''; })));
console.log("Example 2: " + JSON.stringify(arr.filter(function(entry) { return /\S/.test(entry); })));
var rex = /\S/;
console.log("Example 3: " + JSON.stringify(arr.filter(rex.test.bind(rex))));

...and the ES2015 (ES6) ones (won't work if your browser doesn't support arrow functions yet):

var arr = ['Apple', '  ', 'Mango', '', 'Banana', ' ', 'Strawberry'];
console.log("Example 4: " + JSON.stringify(arr.filter(entry => !entry.trim() == '')));
console.log("Example 5: " + JSON.stringify(arr.filter(entry => /\S/.test(entry))));
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • It's slightly cleaner to say `!/\S/.test(entry)`. –  Feb 18 '16 at 09:09
  • @torazaburo: Actually, **all** of my examples were backward! – T.J. Crowder Feb 18 '16 at 09:11
  • @Daniel: Classic morning mental fail. Fixed. :-) – T.J. Crowder Feb 18 '16 at 09:14
  • @T.J.Crowder : Is there a reason why your first/second example would not remove the first element of an array if that contained just a single whitespace character? – user3001499 Sep 20 '17 at 14:43
  • @user3001499: No, why? – T.J. Crowder Sep 20 '17 at 14:45
  • @T.J.Crowder - I have a script where I have used this example, the first element is a single whitespace character and it isn't being removed (all subsequent whitespace elements are though). I wondered if it's a bug elsewhere in my code or an idiosyncrasy of this method. Must be a bug on my part! – user3001499 Sep 20 '17 at 14:48
  • I got an error with example 1 `Execution failed: TypeError: Cannot find function trim in object `. Example 2 worked for my purposes. – DanCue Aug 02 '18 at 13:31
  • @DaniloCuellar - Sounds like you're running the code in an outdated environment (like IE). `trim` was added to strings in ES2015. It can be easily polyfilled if needed. – T.J. Crowder Aug 03 '18 at 07:55
  • @T.J.Crowder I'm on Chrome. Either way, example 2 is working for me. I appreciate it. – DanCue Aug 03 '18 at 11:33
  • @DaniloCuellar - That tells me that `entry` isn't a string in your scenario. Passing a non-string into `test` will convert it to a string. – T.J. Crowder Aug 03 '18 at 11:55
20

You can take advantage of empty string as falsy value.

You can use Array#filter with String#trim.

Using ES6 Arrow function:

arr = arr.filter(e => String(e).trim());

var arr = ['Apple', '  ', 'Mango', '', 'Banana', ' ', 'Strawberry'];
var nonEmpty = arr.filter(e => String(e).trim());

document.getElementById('result').innerHTML = JSON.stringify(nonEmpty, 0, 4);
<pre id="result"></pre>

Using ES5 anonymous function:

arr = arr.filter(function(e) {
    return String(e).trim();
});

var arr = ['Apple', '  ', 'Mango', '', 'Banana', ' ', 'Strawberry'];
var nonEmpty = arr.filter(function(e) {
    return String(e).trim();
});

document.getElementById('result').innerHTML = JSON.stringify(nonEmpty, 0, 4);
<pre id="result"></pre>
Tushar
  • 85,780
  • 21
  • 159
  • 179
4

Based on this MDN reference:

\s
Matches a single white space character, including space, tab, form feed, line feed and other Unicode spaces. Equivalent to [ \f\n\r\t\v​\u00a0\u1680​\u180e\u2000​-\u200a​\u2028\u2029\u202f\u205f​\u3000\ufeff].

And on ECMA 262 reference, saying \s should match "White Space" like \u0009 (Tab, <TAB>), \u000B (Vertical Tab, <VT>), \u000C (Form Feed, <FF>), \u0020 (Space, <SP>), \u00A0 (No-break space, <NBSP>), \uFEFF (Byte Order Mark, <BOM>), and other category “Zs” (<USP>), and also "line terminators" like \u000A (Line Feed, <LF>), \u000D (Carriage Return, <CR>), \u2028 (Line separator, <LS>) and \u2029 (Paragraph separator, <PS>), you can use the following code to remove elements that are either empty or whitespace only if trim() is not natively available:

var arr = ['Apple', '  ', 'Mango', '', 'Banana', ' ', 'Strawberry'];
arr = arr.filter(s => s.replace(/\s+/g, '').length !== 0);
// Or for ES5
// arr = arr.filter(function (el) { return el.replace(/\s+/g, '').length !== 0; });
console.log(arr);

In case some old browsers behave differently with \s, replace it with [ \f\n\r\t\v​\u00a0\u1680​\u180e\u2000​-\u200a​\u2028\u2029\u202f\u205f​\u3000\ufeff] character class:

arr = arr.filter(function (el) { return el.replace(/[ \f\n\r\t\v​\u00a0\u1680​\u180e\u2000​-\u200a​\u2028\u2029\u202f\u205f​\u3000\ufeff]+/g, '').length !== 0; });

And you can also customize it further to include new Unicode spaces to come.

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • I would just use `\s`, but [MDN `trim()` reference page](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/Trim) suggests this regexp. If we really need to support *all* Unicode whitespace, we'd need to add more characters to the character class. – Wiktor Stribiżew Feb 18 '16 at 09:11
  • But doesn't `\s` include `\xA0` (and couldn't that be written more simply as `\n`)? –  Feb 18 '16 at 09:14
  • MDN is written by mere mortals and should not be considered holy writ. It is very clear that `\s` includes `\n`, which is the same as `\x0a`. So the regexp given on that MDN page is wrong, or at least redundant. –  Feb 18 '16 at 09:17
  • @torazaburo: It seems you are right, though `\x0A` matches a hard space (not a newline). I think I need to ransack the ECMAScript documentation to check that. – Wiktor Stribiżew Feb 18 '16 at 09:17
  • 1
    I don't know what "hard space" means. According to MDN regexp page, "\n Matches a line feed (U+000A)." –  Feb 18 '16 at 09:23
  • @torazaburo: `\xA0` != `\x0A`, "hard" = "nonbreaking". BTW, *MDN is written by mere mortals* means there is some reference written by the gods? :) Would you mind sharing a link? – Wiktor Stribiżew Feb 18 '16 at 09:27
  • Sorry about my dyslexic confusion. But the fact remains that `\s` apparently DOES include `\xa0` (non-breaking space). –  Feb 18 '16 at 09:30
  • @WiktorStribiżew: Still mere mortals, but with a more robust review process: [The specification](http://www.ecma-international.org/ecma-262/6.0/index.html#sec-characterclassescape), which tells us that `\s` matches [everything here](http://www.ecma-international.org/ecma-262/6.0/index.html#sec-white-space) and [everything here](http://www.ecma-international.org/ecma-262/6.0/index.html#sec-line-terminators). Which includes `\xA0` and all other Unicode space chars. For at least some time, several implementations in the wild failed to follow the spec, which is probably why MDN says that. – T.J. Crowder Feb 18 '16 at 09:42
  • @T.J.Crowder: I have just found that: http://www.ecma-international.org/ecma-262/5.1/#sec-7.2 – Wiktor Stribiżew Feb 18 '16 at 09:42
  • @WiktorStribiżew: Yup, but `\s` also matches line terminators. That's the old spec, but this part didn't change (in substance; just presentation). – T.J. Crowder Feb 18 '16 at 09:48
  • 1
    Yeah, I added all the relevant details to the answer. I hope it is now complete and helpful to those who seek understanding what is behind `\s` :) – Wiktor Stribiżew Feb 18 '16 at 09:53
0

You Can try this approach. I found this process simple and it work for me.

let arrayEle = ["abc", " "," ", "def", "xyz", " "]; 

  arrayEle = arrayEle.filter((element) => {
    return /\S/.test(element);
  });
  
  console.log(arrayEle);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
Atit More
  • 137
  • 7
0

const fruits = ['Apple', undefined, ' ', 'Mango', '', 'Banana', ' ', 'Strawberry'];

fruits.filter(fruit => fruit && fruit.trim())

Output: ["Apple", "Mango", "Banana", "Strawberry"]

Filter condition: fruit && fruit.trim()

prefix - will remove all the falsy value
suffix - will trim and then remove all the falsy values

0

A one-line solution written in ES6 for quick use:

const filterArray=a=>a.filter(x=>typeof x!=='string'||!!x.trim())

Some advantages of this are that it ignores anything that is not a string.

Without ES6:

function filterArray(a) {
  return a.filter(function(x) {
    return typeof x !== 'string' || !!x.trim()
  })
}

Example:

const filterArray=a=>a.filter(x=>typeof x!=='string'||!!x.trim())

console.log(filterArray([1, 2, 4, '', '']))

Or if your browser doesn't support ES6 (which it probably does):

function filterArray(a) {
  return a.filter(function(x) {
    return typeof x !== 'string' || !!x.trim()
  })
}

console.log(filterArray([1, 2, 4, '', '']))
shreyasm-dev
  • 2,711
  • 5
  • 16
  • 34
0

I used filter and checking if element length is not equal to zero. It worked for me, and this solution is short:

const arr = ['Apple', '', 'Mango', '', 'Banana', '', 'Strawberry']

const arr2 = arr.filter(item => item.length !== 0)          

console.log(arr2)
Vic_Gayday
  • 11
  • 3
0
function clearSpace(arr){
    for (var key in arr) {
        if (arr[key] == "") {
            arr.splice(key, 1)
            clearSpace(arr)
        }
    }
}
var arr = ["","a","b","",""]
clearSpace(arr)
console.log(arr)

//I hope this helps you!!
//Vu Tien Luong - 3GTEL
-1

Could use Array.protype.join(), String.prototype.split() with parameter RegExp /\s|,/ followed by .filter(Boolean)

var arr = ['Apple', '  ', 'Mango', '', 'Banana', ' ', 'Strawberry'];
arr = arr.join().split(/\s|,/).filter(Boolean);
console.log(arr)
guest271314
  • 1
  • 15
  • 104
  • 177
  • This is a horrible idea. What if an element in the array contains internal whitespace, like `"My name is Guest271314"`, or a comma? –  Feb 18 '16 at 09:19
  • @torazaburo `["My name is a b c", 'Apple', ' ', 'Mango', '', 'Banana', ' ', 'Strawberry'].join("~").split(/~\s+~|\s(?=\s+)|~?~/)` – guest271314 Feb 18 '16 at 09:53
  • Now it won't work if the strings in the array have a tilde in them. –  Feb 18 '16 at 12:46
  • @torazaburo `["My name is, a b c", "Apple", " ", "Mango", "", "Banana", " ", "Strawberry"].join(" "/* two space characters */).replace(/\s{2,}/g, "DELIM").split("DELIM")` – guest271314 Feb 18 '16 at 16:31