String.prototype.search()

Returns the index of the first regular expression match, or -1 if there is none.

Signature
search(regexp)
  • Added in JavaScript ES1

Parameters

ParameterTypeDescription
$regexpoptionalRegExp | { [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 makes search() 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

Try it yourself
Loading editor…
Press Run to execute the code.

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.

Example · javascript
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 1

Splitting 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.

Example · javascript
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.

Example · javascript
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

  • Be the first to comment on this lesson.