How do I perform case insensitive string comparison in JavaScript?
This question is related to
javascript
string
Suppose we want to find the string variable needle
in the string variable haystack
. There are three gotchas:
string.toUpperCase
and string.toLowerCase
. Use a regular expression which ignores case instead. For example, var needleRegExp = new RegExp(needle, "i");
followed by needleRegExp.test(haystack)
.needle
. Be careful that needle
does not contain any regular expression special characters. Escape these using needle.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
.needle
and haystack
, just ignoring case, make sure to add "^"
at the start and "$"
at the end of your regular expression constructor.Taking points (1) and (2) into consideration, an example would be:
var haystack = "A. BAIL. Of. Hay.";
var needle = "bail.";
var needleRegExp = new RegExp(needle.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), "i");
var result = needleRegExp.test(haystack);
if (result) {
// Your code here
}
if you are concerned about the direction of the inequality (perhaps you want to sort a list) you pretty-much have to do case-conversion, and as there are more lowercase characters in unicode than uppercase toLowerCase is probably the best conversion to use.
function my_strcasecmp( a, b )
{
if((a+'').toLowerCase() > (b+'').toLowerCase()) return 1
if((a+'').toLowerCase() < (b+'').toLowerCase()) return -1
return 0
}
Javascript seems to use locale "C" for string comparisons so the resulting ordering will be ugly if the strings contain other than ASCII letters. there's not much that can be done about that without doing much more detailed inspection of the strings.
If you know you're dealing with ascii
text then you can just use a uppercase/lowercase character offset comparison.
Just make sure the string your "perfect" string (the one you want to match against) is lowercase:
const CHARS_IN_BETWEEN = 32;
const LAST_UPPERCASE_CHAR = 90; // Z
function strMatchesIgnoreCase(lowercaseMatch, value) {
let i = 0, matches = lowercaseMatch.length === value.length;
while (matches && i < lowercaseMatch.length) {
const a = lowercaseMatch.charCodeAt(i);
const A = a - CHARS_IN_BETWEEN;
const b = value.charCodeAt(i);
const B = b + ((b > LAST_UPPERCASE_CHAR) ? -CHARS_IN_BETWEEN : CHARS_IN_BETWEEN);
matches = a === b // lowerA === b
|| A === b // upperA == b
|| a === B // lowerA == ~b
|| A === B; // upperA == ~b
i++;
}
return matches;
}
Since no answer clearly provided a simple code snippet for using RegExp
, here's my attempt:
function compareInsensitive(str1, str2){
return typeof str1 === 'string' &&
typeof str2 === 'string' &&
new RegExp("^" + str1.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + "$", "i").test(str2);
}
It has several advantages:
undefined
for example, would crash an expression like str1.toUpperCase()
).RegExp
string.Remember that casing is a locale specific operation. Depending on scenario you may want to take that in to account. For example, if you are comparing names of two people you may want to consider locale but if you are comparing machine generated values such as UUID then you might not. This why I use following function in my utils library (note that type checking is not included for performance reason).
function compareStrings (string1, string2, ignoreCase, useLocale) {
if (ignoreCase) {
if (useLocale) {
string1 = string1.toLocaleLowerCase();
string2 = string2.toLocaleLowerCase();
}
else {
string1 = string1.toLowerCase();
string2 = string2.toLowerCase();
}
}
return string1 === string2;
}
Convert both to lower (only once for performance reasons) and compare them with ternary operator in a single line:
function strcasecmp(s1,s2){
s1=(s1+'').toLowerCase();
s2=(s2+'').toLowerCase();
return s1>s2?1:(s1<s2?-1:0);
}
This is an improved version of this answer.
String.equal = function (s1, s2, ignoreCase, useLocale) {
if (s1 == null || s2 == null)
return false;
if (!ignoreCase) {
if (s1.length !== s2.length)
return false;
return s1 === s2;
}
if (useLocale) {
if (useLocale.length)
return s1.toLocaleLowerCase(useLocale) === s2.toLocaleLowerCase(useLocale)
else
return s1.toLocaleLowerCase() === s2.toLocaleLowerCase()
}
else {
if (s1.length !== s2.length)
return false;
return s1.toLowerCase() === s2.toLowerCase();
}
}
String.equal = function (s1, s2, ignoreCase, useLocale) {_x000D_
if (s1 == null || s2 == null)_x000D_
return false;_x000D_
_x000D_
if (!ignoreCase) {_x000D_
if (s1.length !== s2.length)_x000D_
return false;_x000D_
_x000D_
return s1 === s2;_x000D_
}_x000D_
_x000D_
if (useLocale) {_x000D_
if (useLocale.length)_x000D_
return s1.toLocaleLowerCase(useLocale) === s2.toLocaleLowerCase(useLocale)_x000D_
else_x000D_
return s1.toLocaleLowerCase() === s2.toLocaleLowerCase()_x000D_
}_x000D_
else {_x000D_
if (s1.length !== s2.length)_x000D_
return false;_x000D_
_x000D_
return s1.toLowerCase() === s2.toLowerCase();_x000D_
}_x000D_
}_x000D_
_x000D_
// If you don't mind extending the prototype._x000D_
String.prototype.equal = function(string2, ignoreCase, useLocale) {_x000D_
return String.equal(this.valueOf(), string2, ignoreCase, useLocale);_x000D_
}_x000D_
_x000D_
// ------------------ TESTS ----------------------_x000D_
console.log("Tests...");_x000D_
_x000D_
console.log('Case sensitive 1');_x000D_
var result = "Abc123".equal("Abc123");_x000D_
console.assert(result === true);_x000D_
_x000D_
console.log('Case sensitive 2');_x000D_
result = "aBC123".equal("Abc123");_x000D_
console.assert(result === false);_x000D_
_x000D_
console.log('Ignore case');_x000D_
result = "AbC123".equal("aBc123", true);_x000D_
console.assert(result === true);_x000D_
_x000D_
console.log('Ignore case + Current locale');_x000D_
result = "AbC123".equal("aBc123", true);_x000D_
console.assert(result === true);_x000D_
_x000D_
console.log('Turkish test 1 (ignore case, en-US)');_x000D_
result = "IiiI".equal("iiII", true, "en-US");_x000D_
console.assert(result === false);_x000D_
_x000D_
console.log('Turkish test 2 (ignore case, tr-TR)');_x000D_
result = "IiiI".equal("iiII", true, "tr-TR");_x000D_
console.assert(result === true);_x000D_
_x000D_
console.log('Turkish test 3 (case sensitive, tr-TR)');_x000D_
result = "IiiI".equal("iiII", false, "tr-TR");_x000D_
console.assert(result === false);_x000D_
_x000D_
console.log('null-test-1');_x000D_
result = "AAA".equal(null);_x000D_
console.assert(result === false);_x000D_
_x000D_
console.log('null-test-2');_x000D_
result = String.equal(null, "BBB");_x000D_
console.assert(result === false);_x000D_
_x000D_
console.log('null-test-3');_x000D_
result = String.equal(null, null);_x000D_
console.assert(result === false);
_x000D_
With the help of regular expression also we can achieve.
(/keyword/i).test(source)
/i
is for ignore case. If not necessary we can ignore and test for NOT case sensitive match like
(/keyword/).test(source)
Use RegEx for string match or comparison.
In JavaScript, you can use match()
for string comparison,
don't forget to put i
in RegEx.
Example:
var matchString = "Test";
if (matchString.match(/test/i)) {
alert('String matched');
}
else {
alert('String not matched');
}
If both strings are of the same known locale, you may want to use Intl.Collator
object like this:
function equalIgnoreCase(s1: string, s2: string) {
return new Intl.Collator("en-US", { sensitivity: "base" }).compare(s1, s2) === 0;
}
Obviously, you may want to cache the Collator
for better efficiency.
The advantages of this approach is that it should be much faster than using RegExps and is based on an extremely customizable (see description of locales
and options
constructor parameters in the article above) set of ready-to-use collators.
Even this question have already answered. I have a different approach to use RegExp and match to ignore case sensitive. Please see my link https://jsfiddle.net/marchdave/7v8bd7dq/27/
$("#btnGuess").click(guessWord);
function guessWord() {
var letter = $("#guessLetter").val();
var word = 'ABC';
var pattern = RegExp(letter, 'gi'); // pattern: /a/gi
var result = word.match(pattern);
alert('Ignore case sensitive:' + result);
}
I like this quick shorthand variation -
export const equalsIgnoreCase = (str1, str2) => {
return (!str1 && !str2) || (str1 && str2 && str1.toUpperCase() == str2.toUpperCase())
}
Quick in processing, and does what it is intended to.
As said in recent comments, string::localeCompare
supports case insensitive comparisons (among other powerful things).
Here's a simple example
'xyz'.localeCompare('XyZ', undefined, { sensitivity: 'base' }); // returns 0
And a generic function you could use
function equalsIgnoringCase(text, other) {
return text.localeCompare(other, undefined, { sensitivity: 'base' }) === 0;
}
Note that instead of undefined
you should probably enter the specific locale you are working with. This is important as denoted in the MDN docs
in Swedish, ä and a are separate base letters
As of time of posting, UC Browser for Android and Opera Mini do not support locale and options parameters. Please check https://caniuse.com/#search=localeCompare for up to date info.
I have recently created a micro library that provides case-insensitive string helpers: https://github.com/nickuraltsev/ignore-case. (It uses toUpperCase
internally.)
var ignoreCase = require('ignore-case');
ignoreCase.equals('FOO', 'Foo'); // => true
ignoreCase.startsWith('foobar', 'FOO'); // => true
ignoreCase.endsWith('foobar', 'BaR'); // => true
ignoreCase.includes('AbCd', 'c'); // => true
ignoreCase.indexOf('AbCd', 'c'); // => 2
str = 'Lol', str2 = 'lOl', regex = new RegExp('^' + str + '$', 'i');
if (regex.test(str)) {
console.log("true");
}
EDIT: This answer was originally added 9 years ago. Today you should use localeCompare
with the sensitivity: 'accent'
option:
function ciEquals(a, b) {_x000D_
return typeof a === 'string' && typeof b === 'string'_x000D_
? a.localeCompare(b, undefined, { sensitivity: 'accent' }) === 0_x000D_
: a === b;_x000D_
}_x000D_
_x000D_
console.log("'a' = 'a'?", ciEquals('a', 'a'));_x000D_
console.log("'AaA' = 'aAa'?", ciEquals('AaA', 'aAa'));_x000D_
console.log("'a' = 'á'?", ciEquals('a', 'á'));_x000D_
console.log("'a' = 'b'?", ciEquals('a', 'b'));
_x000D_
The { sensitivity: 'accent' }
tells localeCompare()
to treat two variants of the same base letter as the same unless they have different accents (as in the third example) above.
Alternatively, you can use { sensitivity: 'base' }
, which treats two characters as equivalent as long as their base character is the same (so A
would be treated as equivalent to á
).
Note that the third parameter of localeCompare
is not supported in IE10 or lower or certain mobile browsers (see the compatibility chart on the page linked above), so if you need to support those browsers, you'll need some kind of fallback:
function ciEqualsInner(a, b) {
return a.localeCompare(b, undefined, { sensitivity: 'accent' }) === 0;
}
function ciEquals(a, b) {
if (typeof a !== 'string' || typeof b !== 'string') {
return a === b;
}
// v--- feature detection
return ciEqualsInner('A', 'a')
? ciEqualsInner(a, b)
: /* fallback approach here */;
}
Original answer
The best way to do a case insensitive comparison in JavaScript is to use RegExp match()
method with the i
flag.
When both strings being compared are variables (not constants), then it's a little more complicated 'cause you need to generate a RegExp from the string but passing the string to RegExp constructor can result in incorrect matches or failed matches if the string has special regex characters in it.
If you care about internationalization don't use toLowerCase()
or toUpperCase()
as it doesn't provide accurate case-insensitive comparisons in all languages.
I wrote a extension. very trivial
if (typeof String.prototype.isEqual!= 'function') {
String.prototype.isEqual = function (str){
return this.toUpperCase()==str.toUpperCase();
};
}
For better browser compatibility you can rely on a regular expression. This will work in all web browsers released in the last 20 years:
String.prototype.equalsci = function(s) {
var regexp = RegExp("^"+this.replace(/[.\\+*?\[\^\]$(){}=!<>|:-]/g, "\\$&")+"$", "i");
return regexp.test(s);
}
"PERSON@Ü.EXAMPLE.COM".equalsci("person@ü.example.com")// returns true
This is different from the other answers found here because it takes into account that not all users are using modern web browsers.
Note: If you need to support unusual cases like the Turkish language you will need to use localeCompare because i and I are not the same letter in Turkish.
"I".localeCompare("i", undefined, { sensitivity:"accent"})===0// returns true
"I".localeCompare("i", "tr", { sensitivity:"accent"})===0// returns false
How about NOT throwing exceptions and NOT using slow regex?
return str1 != null && str2 != null
&& typeof str1 === 'string' && typeof str2 === 'string'
&& str1.toUpperCase() === str2.toUpperCase();
The above snippet assumes you don't want to match if either string is null or undefined.
If you want to match null/undefined, then:
return (str1 == null && str2 == null)
|| (str1 != null && str2 != null
&& typeof str1 === 'string' && typeof str2 === 'string'
&& str1.toUpperCase() === str2.toUpperCase());
If for some reason you care about undefined vs null:
return (str1 === undefined && str2 === undefined)
|| (str1 === null && str2 === null)
|| (str1 != null && str2 != null
&& typeof str1 === 'string' && typeof str2 === 'string'
&& str1.toUpperCase() === str2.toUpperCase());
Lots of answers here, but I like to add a sollution based on extending the String lib:
String.prototype.equalIgnoreCase = function(str)
{
return (str != null
&& typeof str === 'string'
&& this.toUpperCase() === str.toUpperCase());
}
This way you can just use it like you do in Java!
Example:
var a = "hello";
var b = "HeLLo";
var c = "world";
if (a.equalIgnoreCase(b)) {
document.write("a == b");
}
if (a.equalIgnoreCase(c)) {
document.write("a == c");
}
if (!b.equalIgnoreCase(c)) {
document.write("b != c");
}
Output will be:
"a == b"
"b != c"
String.prototype.equalIgnoreCase = function(str) {_x000D_
return (str != null &&_x000D_
typeof str === 'string' &&_x000D_
this.toUpperCase() === str.toUpperCase());_x000D_
}_x000D_
_x000D_
_x000D_
var a = "hello";_x000D_
var b = "HeLLo";_x000D_
var c = "world";_x000D_
_x000D_
if (a.equalIgnoreCase(b)) {_x000D_
document.write("a == b");_x000D_
document.write("<br>");_x000D_
}_x000D_
if (a.equalIgnoreCase(c)) {_x000D_
document.write("a == c");_x000D_
}_x000D_
if (!b.equalIgnoreCase(c)) {_x000D_
document.write("b != c");_x000D_
}
_x000D_
There are two ways for case insensitive comparison:
===
). How strict operator treats operands read stuff at:
http://www.thesstech.com/javascript/relational-logical-operatorsUse the "search" string method for case insensitive search. Read about search and other string methods at: http://www.thesstech.com/pattern-matching-using-string-methods
<!doctype html>
<html>
<head>
<script>
// 1st way
var a = "apple";
var b = "APPLE";
if (a.toUpperCase() === b.toUpperCase()) {
alert("equal");
}
//2nd way
var a = " Null and void";
document.write(a.search(/null/i));
</script>
</head>
</html>
Source: Stackoverflow.com