String Searching Techniques

Learn String Searching Techniques with practical examples, explanations, best practices, and real-world coding techniques.

What Is String Searching?

String searching is the process of finding a character, word, substring, or pattern inside a larger string. It is one of the most common operations performed on text and is used in applications such as search boxes, text editors, validation systems, log processing, and pattern matching.

For example, given the string "Learning JavaScript", we may want to determine whether "JavaScript" exists inside it or find the exact position where it begins.

Searching for a Character

The simplest form of string searching is finding a particular character. A string can be traversed from left to right until the required character is found.

const text = "developer";
const target = "v";

for (let i = 0; i < text.length; i++) {
  if (text[i] === target) {
    console.log("Found at index:", i);
    break;
  }
}

This is a basic linear search. In the worst case, every character must be examined.

Using includes()

JavaScript provides the includes() method for checking whether a string contains another string. It returns true when the specified value exists and false otherwise.

const text = "Learn Data Structures";

console.log(text.includes("Data")); // true
console.log(text.includes("Python")); // false

This is often the clearest choice when the requirement is simply to determine whether a substring exists.

Finding the Position With indexOf()

When the position of a character or substring is required, indexOf() can be used. It returns the index of the first occurrence.

const text = "JavaScript Programming";

console.log(text.indexOf("JavaScript")); // 0
console.log(text.indexOf("Programming")); // 11
console.log(text.indexOf("Python")); // -1

A return value of -1 means that the requested value was not found.

Finding the Last Occurrence

Sometimes a value appears multiple times and the position of its final occurrence is needed. The lastIndexOf() method searches from the end and returns the last matching position.

const text = "banana";

console.log(text.indexOf("a"));     // 1
console.log(text.lastIndexOf("a")); // 5

Checking the Beginning and End

String searching is not always about finding a value anywhere in the text. Sometimes a value must occur specifically at the beginning or end. JavaScript provides startsWith() and endsWith() for these cases.

const fileName = "resume.pdf";

console.log(fileName.startsWith("resume")); // true
console.log(fileName.endsWith(".pdf"));      // true
console.log(fileName.endsWith(".jpg"));      // false

Case-Sensitive Searching

JavaScript string searches are case-sensitive by default. Therefore, uppercase and lowercase characters are treated as different values.

const text = "JavaScript";

console.log(text.includes("Java"));       // true
console.log(text.includes("javascript"));  // false
console.log(text.includes("JAVASCRIPT"));  // false

Whether case sensitivity should matter depends on the requirements of the application or problem.

Case-Insensitive String Searching

For a case-insensitive search, both the source string and the search value can be normalized to the same case before searching.

const text = "Learn JavaScript";
const search = "javascript";

const found = text
  .toLowerCase()
  .includes(search.toLowerCase());

console.log(found); // true

Normalizing both values is important. Converting only one side can produce incorrect search results.

Manual Substring Search

A substring search can be implemented without using built-in search methods. The basic approach checks whether the characters of the target substring match consecutive characters in the source string.

function containsSubstring(text, target) {
  if (target.length === 0) {
    return true;
  }

  if (target.length > text.length) {
    return false;
  }

  for (let i = 0; i <= text.length - target.length; i++) {
    let matched = true;

    for (let j = 0; j < target.length; j++) {
      if (text[i + j] !== target[j]) {
        matched = false;
        break;
      }
    }

    if (matched) {
      return true;
    }
  }

  return false;
}

console.log(containsSubstring("javascript", "script"));
// true

This is the basic idea behind naive substring searching. For every possible starting position, the algorithm compares the target substring character by character.

How Naive String Search Works

Suppose we search for "cat" inside "concatenate". The algorithm begins at the first possible position and compares the target characters. If a mismatch occurs, it moves to the next possible starting position.

Text:    c o n c a t e n a t e
Target:  c a t

Start at index 0:
c matches c
o does not match a

Move to the next position and continue...

The algorithm stops when all target characters match or when there are no remaining positions where the target can fit.

Searching for All Occurrences

Sometimes finding the first occurrence is not enough. An algorithm may need to locate every occurrence of a character or substring. A traversal can continue after a match instead of stopping immediately.

const text = "banana";
const target = "a";
const positions = [];

for (let i = 0; i < text.length; i++) {
  if (text[i] === target) {
    positions.push(i);
  }
}

console.log(positions);
// [1, 3, 5]

Searching With a Starting Position

indexOf() accepts an optional starting position. This makes it possible to continue searching after an earlier match.

const text = "banana";

const first = text.indexOf("a");
const second = text.indexOf("a", first + 1);

console.log(first);  // 1
console.log(second); // 3

This technique can be repeated when all occurrences need to be located.

Searching After Normalizing Input

Real-world text may contain extra spaces, punctuation, or inconsistent capitalization. If these differences should not affect the search, the input can be normalized before searching.

const text = "  Learn JavaScript Programming!  ";
const search = "javascript";

const normalizedText = text
  .trim()
  .toLowerCase();

const found = normalizedText.includes(
  search.toLowerCase()
);

console.log(found); // true

The exact normalization rules should depend on the problem. Removing punctuation or spaces without a requirement to do so can change the meaning of the input.

Searching With Regular Expressions

JavaScript also supports regular expressions for pattern-based searching. They are useful when the search requirement is more complex than finding an exact substring.

const text = "Order ID: 12345";

const pattern = /\d+/;

console.log(pattern.test(text));
// true

Regular expressions can match patterns such as digits, whitespace, repeated characters, and structured text. However, for a simple literal search, methods such as includes() are generally easier to read.

Common String Search Approaches

Approach Use Case Typical Idea
Character traversal Find a character Check characters one by one
includes() Check substring existence Returns true or false
indexOf() Find first position Returns index or -1
lastIndexOf() Find final position Searches for last occurrence
Manual substring search Learn or implement matching logic Compare target at each possible position
Regular expression Pattern-based search Match a defined pattern

String Search Complexity

Searching for a single character using a simple traversal takes O(n) time in the worst case for a string of length n. A basic naive substring search can take O(n × m) time, where n is the length of the text and m is the length of the target pattern.

More advanced pattern-matching algorithms such as KMP and Boyer-Moore can reduce unnecessary comparisons for particular workloads. These algorithms are useful when string searching becomes a performance-sensitive problem.

KMP and Advanced Pattern Searching

The Knuth-Morris-Pratt (KMP) algorithm improves substring searching by preprocessing the pattern. It builds a prefix table that helps determine how far the search can move after a mismatch instead of starting the comparison from scratch.

KMP is an important example of how understanding basic string traversal leads to more advanced algorithmic techniques. It is particularly useful when the same pattern needs to be searched efficiently within a text.

Choosing a String Search Technique

The right search technique depends on the requirement. For a simple existence check, a built-in method is usually sufficient. For learning algorithms or solving an interview problem, implementing the search manually may be required. For large-scale or repeated pattern matching, specialized algorithms can provide better performance.

Common Mistakes

  • Forgetting that JavaScript string searches are case-sensitive by default.
  • Treating indexOf() returning -1 as a valid position.
  • Using indexOf() when the requirement is to find every occurrence.
  • Forgetting that substring matching requires consecutive characters.
  • Normalizing only the source string or only the target during case-insensitive searches.
  • Removing spaces or punctuation without confirming that the problem requires normalization.
  • Using complex regular expressions for simple literal searches.
  • Using nested loops without considering the resulting time complexity.

Practical Applications

String searching is used in many software systems where text needs to be located or matched.

  • Search boxes and autocomplete features
  • Text editors and document search
  • Finding keywords in articles and documentation
  • URL and file-extension validation
  • Log analysis and monitoring systems
  • Input validation
  • Source-code analysis
  • Pattern matching and text processing
  • Search engines and indexing systems
  • Coding interview problems

Key Takeaways

  • String searching finds characters, substrings, or patterns inside text.
  • includes() is useful when only existence needs to be checked.
  • indexOf() returns the first matching position or -1.
  • lastIndexOf() finds the final occurrence.
  • Simple character searching can be implemented using linear traversal.
  • Naive substring searching can require O(n × m) comparisons.
  • Case normalization should be applied when a search must be case-insensitive.
  • KMP and other pattern-matching algorithms provide more advanced approaches for efficient searching.

Code Examples

const text = "Learn JavaScript";
const target = "JavaScript";

console.log(text.includes(target));
// true
    
const text = "banana";
const target = "a";
const positions = [];

for (let i = 0; i < text.length; i++) {
  if (text[i] === target) {
    positions.push(i);
  }
}

console.log(positions);
// [1, 3, 5]
    
function containsSubstring(text, target) {
  for (let i = 0; i <= text.length - target.length; i++) {
    let matched = true;

    for (let j = 0; j < target.length; j++) {
      if (text[i + j] !== target[j]) {
        matched = false;
        break;
      }
    }

    if (matched) {
      return true;
    }
  }

  return false;
}

console.log(
  containsSubstring("data structures", "structures")
);
// true
    

Pro Tip

Start by identifying exactly what the search needs to return: a boolean, the first position, every position, or a pattern match. Choosing the simplest operation that satisfies the requirement keeps string-searching code easier to understand and maintain.

🎨 IgKnight Docs

Master HTML, CSS, JS, Python, .NET and more with easy-to-follow lessons and practical code examples.

© 2025 IgKnight Learning Platform. All rights reserved.