{
  "category": "Text functions",
  "display_name": "SEARCHB",
  "entry_kind": "built_in_function",
  "eval_api": {
    "method": "POST",
    "url": "https://handbook.dnacalc.com/api/eval"
  },
  "function_id": "FUNC.SEARCHB",
  "implementation_state": {
    "answer_bank": null,
    "detail": "Recorded: 6 workbook cells.",
    "dnacalc_commit": "9e1884369a678158dd82d3d74188daf986995e87",
    "in_catalogue": true,
    "state": "matches",
    "state_label": "Matches every recorded Excel answer",
    "summary": "Matches all 6 recorded answers",
    "workbook_corpus": {
      "cells": 6,
      "matched": 6
    }
  },
  "implementations": [
    {
      "commit": "9e1884369a678158dd82d3d74188daf986995e87",
      "flavour": "excel-compatibility-candidate",
      "language": "Rust",
      "name": "CalcFunc",
      "own_code": [
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/text_functions.rs#L304-L304"
      ],
      "repository": "https://github.com/DnaCalc/DnaCalc",
      "shared_code": [
        "catalogue/text_functions::count_surrogate_pairs",
        "catalogue/text_functions::single_byte",
        "catalogue/text_functions::start",
        "catalogue/text_functions::search",
        "ported/text_kernels::text",
        "ported/text_kernels::text_from_str",
        "ported/text_kernels::unit_width",
        "ported/text_kernels::character_boundary",
        "ported/text_kernels::slice_character_count",
        "ported/text_kernels::truncated",
        "ported/text_kernels::positive",
        "ported/text_kernels::fold_unit",
        "ported/text_kernels::search_units_equal",
        "ported/text_kernels::search_pattern_matches_prefix",
        "ported/text_kernels::search",
        "ported/text_kernels::push_singleton_or_original",
        "ported/text_kernels::push_lower",
        "ported/text_kernels::lower"
      ],
      "source": "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/text_functions.rs#L304-L304",
      "state": "matches",
      "suite": null,
      "summary": "Matches all 6 recorded answers"
    }
  ],
  "json_url": "https://handbook.dnacalc.com/api/functions/FUNC.SEARCHB.json",
  "name": "SEARCHB",
  "notes": [],
  "schema": "efh.function-reference/v1",
  "section_order": [
    "what-it-does",
    "try-it",
    "quirks",
    "how-to-implement",
    "version-differences",
    "alternatives"
  ],
  "sections": {
    "alternatives": "\n### Relationships\n\n\n- **[SEARCH](FUNC.SEARCH.md)** — the character-position twin, documented by Microsoft on the\n  same page and published by the Handbook as its own entry.\n- **`FINDB`** — the case-sensitive, literal byte locator. See the comparison above.\n- **`LENB`, [MIDB](FUNC.MIDB.md), [REPLACEB](FUNC.REPLACEB.md), `LEFTB`,\n  [RIGHTB](FUNC.RIGHTB.md)** — the rest of the B family. `SEARCHB` is the family's coordinate\n  producer: its output is exactly what `MIDB` and `REPLACEB` expect as `start_num`, and mixing\n  a `SEARCH` result into a `MIDB` call is the classic unit mismatch.\n- **[SUBSTITUTE](FUNC.SUBSTITUTE.md)** — there is no `SUBSTITUTEB`, and that is not an\n  oversight: by-content substitution never needs byte coordinates. Under DBCS it is usually the\n  safer tool.\n\n\n",
    "how-to-implement": "\n### Notes for implementers\n\n\nThe function has to hold two coordinate systems at once: the match runs over characters (the\nwildcard language is defined in characters) and the answer is reported in bytes. That mapping\nhas to be built from the same code-page tables `LENB` uses, or the family will not agree with\nitself.\n\nThe `?`-matches-what question is not an implementation detail to be settled quietly. Pick an\nanswer, document it, mark it unverified, and make it consistent with whatever `MIDB` does at\npartial-character boundaries.\n\nA `SEARCHB` test vector without the default editing language recorded is not a test vector.\n\n\n",
    "quirks": "\n### SEARCHB versus FINDB\n\n\nThe same two-axis distinction as the character pair, restated because it is exactly as\nconfusable at the byte level:\n\n| | `SEARCHB` | `FINDB` |\n|---|---|---|\n| Case | **not** case sensitive | case sensitive |\n| `find_text` is | a **wildcard pattern** (`?`, `*`, `~`) | a **literal** string |\n| Returns | byte position | byte position |\n| Character twin | [SEARCH](FUNC.SEARCH.md) | `FIND` |\n\nChoosing `SEARCHB` over `FINDB` for the case-insensitivity and then passing a `find_text` that\ncontains a literal `*` is the same trap it is on the character functions, and it is no easier\nto spot here.\n\n\n\n### Result and edge cases\n\n\nReturns `Number` — a 1-based byte position.\n\nThe behaviours Microsoft documents for `SEARCH` are stated on the same page for `SEARCHB`:\n`find_text` not found is `#VALUE!`, and a `start_num` outside the valid range is `#VALUE!` —\nwith the range measured in bytes here.\n\nThe distinctively `SEARCHB` questions, none of which the documentation answers:\n\n- **Does `start_num` have to fall on a character boundary?** An odd `start_num` inside a\n  double-byte character is reachable by ordinary arithmetic and is undefined here.\n- **Does `?` match one byte or one character?** Under DBCS these differ, and the wildcard\n  language is documented in terms of characters while the result is measured in bytes. This is\n  the sharpest unresolved question on the page.\n- **Is the returned position always on a character boundary?** It should be if matches only\n  begin at character boundaries, but that is an inference from a rule nobody has stated.\n\n\n### Errors\n\n\nAs documented on Microsoft's `SEARCH, SEARCHB` page:\n\n| Error | Condition |\n|---|---|\n| `#VALUE!` | `find_text` is not found in `within_text`. |\n| `#VALUE!` | `start_num` is not greater than 0, or is greater than the length of `within_text` — in bytes for `SEARCHB`. |\n\nShared coercion errors and error propagation apply as elsewhere. The Handbook has not verified\nany of this against Excel.\n\n\n",
    "sources": "- Microsoft, \"SEARCH, SEARCHB functions\" —\n  <https://support.microsoft.com/en-us/office/search-function-9ab04538-0e55-4719-a72e-b6f54513b495>\n  (signature, case-insensitivity, the wildcard set with the tilde escape, the documented\n  `#VALUE!` conditions, and the DBCS default-language condition for the B family).\n- Handbook, [The value universe](../model/01-value-universe.md) — worksheet text as UTF-16\n  code units, which the byte view must be reconciled against.\n- Handbook, [Coercion and lifting](../model/02-coercion-and-lifting.md) — argument coercion and\n  error propagation.\n\n\n",
    "version-differences": "No comparison between specific Excel builds is recorded here yet. This does not establish that all builds behave alike.",
    "what-it-does": "\n`SEARCHB(find_text, within_text, [start_num])` locates `find_text` inside `within_text` and\nreturns the 1-based **byte** position at which it starts, counted from the beginning of\n`within_text`.\n\nEverything that makes [SEARCH](FUNC.SEARCH.md) what it is carries over unchanged: the match is\n**not case sensitive**, and `find_text` is a **wildcard pattern** in which `?` matches any\nsingle character, `*` matches any sequence, and `~` escapes a following `?` or `*`. The B in\nthe name changes the coordinate system of the answer and the coordinate system of `start_num`.\nIt does not change the matching rule.\n\nAnd the coordinate change itself is conditional. Microsoft's rule for the whole B family:\n\n> The B functions count each double-byte character as 2 **only when a DBCS language has been\n> enabled for editing and set as the default language**. Otherwise they count each character\n> as 1.\n\nSo on a non-DBCS-default installation `SEARCHB` and `SEARCH` return the same numbers for the\nsame inputs. On a Japanese-, Chinese- or Korean-default installation they return different\nnumbers, because the same match sits at a different byte offset than character offset. The\nactive default language is an unlisted input to this function.\n\n\n\n### Arguments\n\n\n| Argument | Meaning | Default |\n|---|---|---|\n| `find_text` | The pattern to look for. Required. | — |\n| `within_text` | The string to look in. Required. | — |\n| `start_num` | 1-based **byte** position at which the scan begins. Optional. | 1 |\n\n`start_num` is in bytes, which is the argument most likely to be wrong in a formula ported from\n`SEARCH`. A `start_num` computed from `LEN` is a character coordinate; feeding it to `SEARCHB`\nis a unit error that produces plausible wrong answers rather than an error value. `LENB` is\nthe function that produces the right coordinates.\n\n\n"
  },
  "signature": {
    "display": "SEARCHB(find_text, within_text, [start_num])",
    "parameters": [
      {
        "description": null,
        "name": "find_text",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "within_text",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "start_num",
        "optional": true,
        "repeats": false
      }
    ],
    "trailing_repeats": false
  },
  "sources": {
    "metadata": {
      "admission": {
        "label": "implemented",
        "reason": null
      },
      "arity": {
        "max": 3,
        "min": 2
      },
      "category": "Text functions",
      "classification": {
        "arg_preparation_profile": "ValuesOnlyPreAdapter",
        "coercion_lift_profile": "None",
        "determinism_class": "Deterministic",
        "error_collapse_profile": "None",
        "fec_dependency_profile": "None",
        "host_interaction_class": "None",
        "kernel_signature_class": "Custom",
        "rich_value_usage": "RichBlind",
        "surface_fec_dependency_profile": "RefOnly",
        "thread_safety_class": "SafePure",
        "volatility_class": "NonVolatile"
      },
      "descriptions": {
        "long": null,
        "short": "Position of one text inside another, ignoring case, counted in bytes for double-byte languages",
        "short_source": "dna-calc-own"
      },
      "docs": {
        "english_description": "Finds one text value within another (not case-sensitive)",
        "microsoft_url": "https://support.microsoft.com/en-us/office/search-function-9ab04538-0e55-4719-a72e-b6f54513b495"
      },
      "entry_kind": "built_in_function",
      "localized_family_names": null,
      "localized_names": [
        {
          "locale": "ar-SA",
          "name": "SEARCHB"
        },
        {
          "locale": "bg-BG",
          "name": "SEARCHB"
        },
        {
          "locale": "cs-CZ",
          "name": "SEARCHB"
        },
        {
          "locale": "da-DK",
          "name": "SØGB"
        },
        {
          "locale": "de-DE",
          "name": "SUCHENB"
        },
        {
          "locale": "el-GR",
          "name": "SEARCHB"
        },
        {
          "locale": "en-AU",
          "name": "SEARCHB"
        },
        {
          "locale": "en-GB",
          "name": "SEARCHB"
        },
        {
          "locale": "en-US",
          "name": "SEARCHB"
        },
        {
          "locale": "es-ES",
          "name": "HALLARB"
        },
        {
          "locale": "et-EE",
          "name": "SEARCHB"
        },
        {
          "locale": "fi-FI",
          "name": "KÄY.LÄPIB"
        },
        {
          "locale": "fr-FR",
          "name": "CHERCHERB"
        },
        {
          "locale": "he-IL",
          "name": "SEARCHB"
        },
        {
          "locale": "hr-HR",
          "name": "SEARCHB"
        },
        {
          "locale": "hu-HU",
          "name": "SZÖVEG.KERES2"
        },
        {
          "locale": "id-ID",
          "name": "SEARCHB"
        },
        {
          "locale": "it-IT",
          "name": "CERCA.B"
        },
        {
          "locale": "ja-JP",
          "name": "SEARCHB"
        },
        {
          "locale": "ko-KR",
          "name": "SEARCHB"
        },
        {
          "locale": "lt-LT",
          "name": "SEARCHB"
        },
        {
          "locale": "lv-LV",
          "name": "SEARCHB"
        },
        {
          "locale": "nb-NO",
          "name": "SØKB"
        },
        {
          "locale": "nl-NL",
          "name": "VIND.SPEC.B"
        },
        {
          "locale": "pl-PL",
          "name": "SZUKAJ.TEKST.B"
        },
        {
          "locale": "pt-BR",
          "name": "LOCALIZARB"
        },
        {
          "locale": "pt-PT",
          "name": "PROCURARB"
        },
        {
          "locale": "ro-RO",
          "name": "SEARCHB"
        },
        {
          "locale": "ru-RU",
          "name": "ПОИСКБ"
        },
        {
          "locale": "sk-SK",
          "name": "SEARCHB"
        },
        {
          "locale": "sl-SI",
          "name": "SEARCHB"
        },
        {
          "locale": "sr-Latn-RS",
          "name": "SEARCHB"
        },
        {
          "locale": "sv-SE",
          "name": "SÖKB"
        },
        {
          "locale": "th-TH",
          "name": "SEARCHB"
        },
        {
          "locale": "tr-TR",
          "name": "ARAB"
        },
        {
          "locale": "uk-UA",
          "name": "SEARCHB"
        },
        {
          "locale": "vi-VN",
          "name": "SEARCHB"
        },
        {
          "locale": "zh-CN",
          "name": "SEARCHB"
        },
        {
          "locale": "zh-HK",
          "name": "SEARCHB"
        },
        {
          "locale": "zh-TW",
          "name": "SEARCHB"
        }
      ],
      "signature": {
        "display": "SEARCHB(find_text, within_text, [start_num])",
        "parameters": [
          {
            "description": null,
            "name": "find_text",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "within_text",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "start_num",
            "optional": true,
            "repeats": false
          }
        ],
        "trailing_repeats": false
      },
      "surface_name": "SEARCHB",
      "version_marker": null,
      "xlcall": null
    },
    "microsoft": "https://support.microsoft.com/en-us/office/search-function-9ab04538-0e55-4719-a72e-b6f54513b495"
  },
  "try_it": {
    "formula": "=SEARCHB(\"語\", \"日本語\")"
  },
  "url": "https://handbook.dnacalc.com/functions/SEARCHB.html",
  "variants": [],
  "versions": []
}