String.prototype.search()
Returns the index of the first regular expression match, or -1 if there is none.
search(regexp)- Added in JavaScript ES1
Parameters
| Parameter | Type | Description |
|---|---|---|
$regexpoptional | RegExp | { [Symbol.search](): any } | A regular expression object, or any object with a Symbol.search method. A value that is neither is implicitly converted with new RegExp(regexp). |
Return value
numberThe index of the first match between the regular expression and the given string, or -1 if no match was found.
search() is the regex counterpart to indexOf(): it answers where rather than whether or what. Use it when a plain substring will not do — you need case-insensitivity, a character class, a word boundary — but you only care about the position.
Choosing between the neighbours
indexOf()— literal substring, position. Faster; no regex engine involved.search()— pattern, position.regexp.test()— pattern, boolean. Cheapest when you only need yes or no.- match() — pattern, the matched text and groups (and
index, which makessearch()redundant if you needed the text anyway).
The g flag does nothing here
Unlike test() and exec(), search() ignores the g flag and never consults or updates lastIndex — the search always behaves as if lastIndex were 0. That makes it safe to call repeatedly with a shared global regex, which is exactly the situation where test() starts alternating between true and false.
Passing a non-regex converts it with new RegExp(), so "a.b".search(".") returns 0, not 1 — the dot is a metacharacter.
Example
When to use it
- Find where the first digit appears in an identifier
- Locate the first uppercase letter to split a camelCase name
- Check case-insensitively where a keyword starts
- Detect the position of the first non-ASCII character
Frequently asked questions
What is the difference between search and indexOf?
search() takes a regular expression while indexOf() takes a literal substring, and search() has no second argument for a start position. Use indexOf() for literal text — it is faster and its metacharacters are not special.
Does the g flag affect String.prototype.search?
No. search() ignores the g flag and never reads or writes the regex's lastIndex, always searching as if lastIndex were 0. That makes it repeatable with a shared global regex, unlike test() and exec().
How do I get both the position and the matched text?
Use match() without the g flag and read the index property of the result, which also gives you the matched text and capture groups. Calling search() and then match() separately runs the regex engine twice for the same information.
More examples
search vs test with a global regex
test() with a global regex advances lastIndex on each call and eventually reports false for a string that clearly matches. search() ignores lastIndex entirely, so repeated calls are stable — the reason it is the safer choice with a shared regex.
const re = /\d/g;
const s = "a1b2";
console.log(re.test(s), re.test(s), re.test(s)); // true true false
re.lastIndex = 0;
console.log(s.search(re), s.search(re), s.search(re)); // 1 1 1Splitting a camelCase identifier
The outputs are "user", "total" and an empty string. The last case shows why the -1 guard matters in reverse: XMLParser matches at index 0, so slicing gives "" — a real edge case for identifier parsing.
function firstWord(name) {
const i = name.search(/[A-Z]/);
return i === -1 ? name : name.slice(0, i);
}
console.log(firstWord("userFirstName"));
console.log(firstWord("total"));
console.log(firstWord("XMLParser"));Finding the first non-ASCII character
The first row reports -1 and "ascii"; the others report the index of é and ï along with the character itself. Getting the position back means you can point at the offending character rather than just flagging the row.
const rows = ["plain text", "café order", "naïve"];
for (const r of rows) {
const i = r.search(/[^\x00-\x7F]/);
console.log(r, i, i === -1 ? "ascii" : r[i]);
}
Discussion