156

I have an array of strings that I need to loop and check against with another passed in string.

var filterstrings = ['firststring','secondstring','thridstring'];
var passedinstring = localStorage.getItem("passedinstring");

for (i = 0; i < filterstrings.lines.length; i++) {
    if (passedinstring.includes(filterstrings[i])) {
        alert("string detected");
    }
}

How do I ensure that case sensitivity is ignored here (preferably by using regex) when filtering, if the var passedinstring were to have strings like FirsTsTriNg or fiRSTStrING?

dthree
  • 19,847
  • 14
  • 77
  • 106
LegendDemonSlayer
  • 1,677
  • 2
  • 9
  • 15
  • Use a common case or create a regex and use something like `.some` along with it – Rajesh Jan 08 '18 at 06:44
  • 8
    This shouldn't be marked as a duplicate. The advantage of using `includes` over regex is that it covers scenarios where your string contains regex special characters. – Joao Jul 07 '18 at 19:54

11 Answers11

101

You can create a RegExp from filterstrings first

var filterstrings = ['firststring','secondstring','thirdstring'];
var regex = new RegExp( filterstrings.join( "|" ), "i");

then test if the passedinstring is there

var isAvailable = regex.test( passedinstring ); 
Marc Gear
  • 2,757
  • 1
  • 20
  • 19
gurvinder372
  • 66,980
  • 10
  • 72
  • 94
  • 7
    Note that firststringtest will also return true here. with ES5, `filterstrings.map((a) => { return a.toLowerCase() }).includes(passedinstring.toLowerCase())` may be a solution for this problem. – Jacob Morris Nov 08 '19 at 14:41
  • 5
    `filterstrings` must be escaped, otherwise you risk ending up with a broken regex, or one with unexpected behavior. – Matteo Italia Nov 24 '20 at 11:33
  • How much slower is this comparing to .includes() ? – trainoasis Feb 10 '21 at 12:45
  • 11
    This shouldn't be an acceptable answer! Whoever seeks for an answer and stumbled upon this answer - BEWARE! this will return `true` for any sub sequence can be found in the array. ```[1,2,3].includes(12) // false new RegExp([1,2,3].join("|"), "i").test(12) // true!!! ["Hello","World"].includes("HelloWorld") // false \n new RegExp(["Hello", "World"].join("|"), "i").test("HelloWorld") // true!!!``` – Tzahi Leh Aug 18 '21 at 13:32
  • 2
    Mapping random strings to regex patterns is not a good idea, unless you really know that those strings won't include special characters. – Robo Robok Nov 20 '21 at 21:44
  • @TzahiLeh yes you are right but that is the behaviour that OP is looking for – shieldgenerator7 Oct 19 '22 at 13:09
  • @RoboRobok if you can't be sure, how do you sanitize the input? – shieldgenerator7 Oct 19 '22 at 13:09
  • @shieldgenerator7 you just compare strings and if it needs to be case-insensitive, compare lower- or uppercased versions of them. Simple as that. – Robo Robok Oct 19 '22 at 13:49
  • @shieldgenerator7 I couldn't understand from the question if this is what the OP wants. Maybe it satisfies the OP, yet I wrote my comment for anyone out there who doesn't know about this regex-behaviour, which can lead to bugs – Tzahi Leh Oct 23 '22 at 09:24
70

ES6 array method filter() can simplify the solution to a single line. Use includes() method to determine whether an array includes a certain value among its entries in conjunction to the toLowerCase() method to convert it to lowercase.

var filterstrings = ['firststring','secondstring','thridstring'];
var passedinstring = localStorage.getItem("passedinstring");

// convert each string from filterstrings and passedinstring to lowercase
// to avoid case sensitive issue.
filteredStrings = filterstrings.filter((str) => str.toLowerCase().includes(passedinstring.toLowerCase())
cngzz1
  • 143
  • 2
  • 9
Kamran Khatti
  • 3,754
  • 1
  • 20
  • 31
  • 2
    this is a great answer! This is a very simple single-line solution. I'm using the `filteredStrings` line within a filter, and I just check if the length > 0 in the encapsulating filter statement – Jan Jul 22 '20 at 21:31
  • 3
    Thanks - its always appreciated when people answer old questions with the latest functionality! – codingbryan Nov 07 '20 at 22:05
  • 2
    Using [localeCompare()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare) would be safer. There can be problems with plain `.toLowerCase()` - please see Jon Skeet's presentation on YouTube [Back to basics: the mess we've made of our fundamental data types](https://youtu.be/l3nPJ-yK-LU?t=1266) for more information. – Andrew Morton Jun 17 '21 at 16:45
  • 2
    I've used a variation on this: filteredstrings = filterstrings.some(e => e.toUpperCase().includes(activeSearch.toUpperCase())) – CosetteN Oct 01 '21 at 17:40
67

You can simply convert the passedinstring to lowercase.

var passedinstring = localStorage.getItem("passedinstring").toLowerCase();
Nabin Paudyal
  • 1,591
  • 8
  • 14
  • 7
    well, it works in the given case but I guess we want it to work the other way around as well... (i.e the filtered strings also having capital letters) – romainm Mar 29 '19 at 09:21
  • 6
    If you want the other way to work as well, just use toLowerCase() on the inputted string as well. – Lengo Jul 16 '21 at 14:32
25

You can switch .includes with the .some method which returns a boolean.
It will exit as soon as a match was found, which is great for performance for huge arrays:

.some(item => item.toLowerCase() == lookup.toLowerCase())

Demo:

var arr = ['foo','bar','bar'];
var lookup = "bAr";

// case-sensetive
console.log( arr.includes(lookup) )

// case-insensetive without caring about the type
console.log( arr.some(x => x.toLowerCase() == lookup.toLowerCase()) ) 

Or define your own Array prototype method with a unique name:

// the name ("_includes") should be unique enough not to ever be overriten 
// by future language updates or 3rd-party scripts
Array.prototype._includes = function(target){ 
  return this.some(x => x.toLowerCase() == (target||'').toLowerCase()) 
}

console.log( 
  ['foo', 'bar', 'bar']._includes("bAr") 
)
vsync
  • 118,978
  • 58
  • 307
  • 400
  • 2
    It could be even better performance-wise, if you do `lookup.toLowerCase()` outside of the loop. – Tomas Loksa Mar 25 '22 at 09:40
  • @TomášLokša - I tend to provide the simplest solution and it is up to the copy-paster to adopt it to their needs. Many answers here can be easily improved by it might not fit everyone or make the solution less easy to understand at a quick glass, which I want to avoid at some situations as this one – vsync Mar 25 '22 at 14:50
  • Ah, got it :) Anyway, thanks for your solution, it was really useful to me. – Tomas Loksa Mar 26 '22 at 18:10
14

convert filterstring and passedinstring to lowercase and compare

var filterstrings = ['firststring','secondstring','thridstring'];
var passedinstring = 
localStorage.getItem("passedinstring").toLowerCase();

for (i = 0; i < filterstrings.lines.length; i++) {
   if (passedinstring.includes(filterstrings[i].toLowerCase())) {
       alert("string detected");
   }
}
Saurabh Mistry
  • 12,833
  • 5
  • 50
  • 71
11

Fixed case sensitivity issue using toLowerCase(). It turns all the strings to lower case.

var product=productList.filter((x) => 
x.Name.toLowerCase().includes(("Active").toLowerCase()))
R15
  • 13,982
  • 14
  • 97
  • 173
5

My option is comparing UPPER with UPPER or lower with lower transforming both sides (i did it often in SQL):

    var filterstrings = ['firststring','secondstring','thirDstrIng'];
    var passedinstring =  'ThIrDsTrInG3';
    
    //used for of just to make it more readable
    for (filterstring of filterstrings) {
        if (passedinstring.toUpperCase().includes(filterstring.toUpperCase())) {
            alert("string detected");
        }
    
    }

Prompts string detected

DDS
  • 2,340
  • 16
  • 34
  • Aha. That's smart. I thought that `.includes()` could only apply to an array. I see that [it can also apply to a string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes). – Rounin Jun 22 '22 at 15:52
3

I believe this would be simpler, shorter and more understandable.

  const q = new RegExp(query, 'i');

  filteredUsers = users.filter((user: User) => {
    return (
      user.entity.short.match(q) ||
      user.firstname.match(q) ||
      user.lastname.match(q)
    );
  });
Mia loha.dev
  • 471
  • 6
  • 13
  • This seems to be filtering a different set of data … and assumes that `query` won't include any characters with special meaning in regular expressions. – Quentin May 18 '21 at 16:22
2
var filterstrings = ['firststring','secondstring','thridstring'];
var passedinstring = localStorage.getItem("passedinstring");

filterstrings.filter(item => item.name.toLowerCase().includes(passedinstring.toLowerCase()))
  • 3
    Your solution is very similar to this one: https://stackoverflow.com/a/63030383/3216427 just replacing `(str) => str.toLowerCase()...` by `item => item.name.toLowerCase()...`. Can you explain what this difference changes and why you think this is an improved solution? – joanis Nov 26 '21 at 14:32
1

A non-regex approach:

I came across this issue yesterday.

I had two arrays, neither of which contained consistently case-formatted values:

let availableDays = [

  'tuesday',
  'THURSDAY',
  'Monday'
];

let orderedWeekdays = [
  
  'Monday',
  'Tuesday',
  'Wednesday',
  'Thursday',
  'FRIDAY'
]

I needed to find out, on a case-insensitive basis, which items from orderedWeekdays were present in availableDays.


Solution:

My non-regex approach was, first, to create a new array for checking:

let availableDays_CheckingArray = availableDays.map((day) => day.toLowerCase());

And then to loop through orderedWeekdays, applying a .toLowerCase() transformation each time, prior to comparing:

for (let i = 0; i < orderedWeekdays.length; i++) {

  if (availableDays_CheckingArray.includes(orderedWeekdays[i].toLowerCase())) {

    [... CODE HERE...]
  }
}
Rounin
  • 27,134
  • 9
  • 83
  • 108
0

You can try this.

var fruits = ["Banana", "Orange", "Apple", "Mango"];
string = fruits.join(' ').toUpperCase();
// Output"BANANA ORANGE APPLE MANGO"
Shantesh Sindgi
  • 265
  • 3
  • 4