Function: string-search

string-search is a function defined in fns.c.

Signature

(string-search NEEDLE HAYSTACK &optional START-POS)

Documentation

Search for the string NEEDLE in the string HAYSTACK.

The return value is the position of the first occurrence of NEEDLE in HAYSTACK, or nil if no match was found.

The optional START-POS argument says where to start searching in HAYSTACK and defaults to zero (start at the beginning). It must be between zero and the length of HAYSTACK, inclusive.

Case is always significant and text properties are ignored.

Other relevant functions are documented in the string group.

Probably introduced at or before Emacs version 28.1.

Shortdoc

;; string
(string-search "bar" "foobarzot")
    => 3

Aliases

tramp-compat-string-search

Source Code

// Defined in /usr/src/emacs/src/fns.c
{
  ptrdiff_t start_byte = 0, haybytes;
  char *res, *haystart;
  EMACS_INT start = 0;

  CHECK_STRING (needle);
  CHECK_STRING (haystack);

  if (!NILP (start_pos))
    {
      CHECK_FIXNUM (start_pos);
      start = XFIXNUM (start_pos);
      if (start < 0 || start > SCHARS (haystack))
        xsignal1 (Qargs_out_of_range, start_pos);
      start_byte = string_char_to_byte (haystack, start);
    }

  /* If NEEDLE is longer than (the remaining length of) haystack, then
     we can't have a match, and return early.  */
  if (SCHARS (needle) > SCHARS (haystack) - start)
    return Qnil;

  haystart = SSDATA (haystack) + start_byte;
  haybytes = SBYTES (haystack) - start_byte;

  /* We can do a direct byte-string search if both strings have the
     same multibyteness, or if the needle consists of ASCII characters only.  */
  if (STRING_MULTIBYTE (haystack)
      ? (STRING_MULTIBYTE (needle)
         || SCHARS (haystack) == SBYTES (haystack) || string_ascii_p (needle))
      : (!STRING_MULTIBYTE (needle)
         || SCHARS (needle) == SBYTES (needle)))
    {
      if (STRING_MULTIBYTE (haystack) && STRING_MULTIBYTE (needle)
          && SCHARS (haystack) == SBYTES (haystack)
          && SCHARS (needle) != SBYTES (needle))
        /* Multibyte non-ASCII needle, multibyte ASCII haystack: impossible.  */
        return Qnil;
      else
        res = memmem (haystart, haybytes,
                      SSDATA (needle), SBYTES (needle));
    }
  else if (STRING_MULTIBYTE (haystack))  /* unibyte non-ASCII needle */
    {
      Lisp_Object multi_needle = string_to_multibyte (needle);
      res = memmem (haystart, haybytes,
		    SSDATA (multi_needle), SBYTES (multi_needle));
    }
  else              /* unibyte haystack, multibyte non-ASCII needle */
    {
      /* The only possible way we can find the multibyte needle in the
	 unibyte stack (since we know that the needle is non-ASCII) is
	 if they contain "raw bytes" (and no other non-ASCII chars.)  */
      ptrdiff_t nbytes = SBYTES (needle);
      for (ptrdiff_t i = 0; i < nbytes; i++)
        {
          int c = SREF (needle, i);
          if (CHAR_BYTE8_HEAD_P (c))
            i++;                /* Skip raw byte.  */
          else if (!ASCII_CHAR_P (c))
            return Qnil;  /* Found a char that can't be in the haystack.  */
        }

      /* "Raw bytes" (aka eighth-bit) are represented differently in
         multibyte and unibyte strings.  */
      Lisp_Object uni_needle = Fstring_to_unibyte (needle);
      res = memmem (haystart, haybytes,
                    SSDATA (uni_needle), SBYTES (uni_needle));
    }

  if (! res)
    return Qnil;

  return make_int (string_byte_to_char (haystack, res - SSDATA (haystack)));
}