{
  "category": "Text functions",
  "display_name": "MID",
  "entry_kind": "built_in_function",
  "eval_api": {
    "method": "POST",
    "url": "https://handbook.dnacalc.com/api/eval"
  },
  "function_id": "FUNC.MID",
  "implementation_state": {
    "answer_bank": null,
    "detail": "Recorded: 14 workbook cells.",
    "dnacalc_commit": "9e1884369a678158dd82d3d74188daf986995e87",
    "in_catalogue": true,
    "state": "matches",
    "state_label": "Matches every recorded Excel answer",
    "summary": "Matches all 14 recorded answers",
    "workbook_corpus": {
      "cells": 14,
      "matched": 14
    }
  },
  "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#L271-L271"
      ],
      "repository": "https://github.com/DnaCalc/DnaCalc",
      "shared_code": [
        "catalogue/text_functions::count_surrogate_pairs",
        "catalogue/text_functions::mid",
        "catalogue/text_functions::start",
        "ported/text_kernels::text",
        "ported/text_kernels::text_from_str",
        "ported/text_kernels::date_integer_floor",
        "ported/text_kernels::nonnegative_count",
        "ported/text_kernels::mid_start",
        "ported/text_kernels::unit_width",
        "ported/text_kernels::character_boundary",
        "ported/text_kernels::take_mid",
        "ported/text_kernels::truncated",
        "ported/text_kernels::positive",
        "ported/text_kernels::push_singleton_or_original",
        "ported/text_kernels::push_upper",
        "ported/text_kernels::upper"
      ],
      "source": "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/text_functions.rs#L271-L271",
      "state": "matches",
      "suite": null,
      "summary": "Matches all 14 recorded answers"
    }
  ],
  "json_url": "https://handbook.dnacalc.com/api/functions/FUNC.MID.json",
  "name": "MID",
  "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- `LEFT` and `RIGHT` are the two anchored slices; `MID` is the free one. `LEFT(t, k)` is\n  `MID(t, 1, k)`, and `RIGHT(t, k)` is `MID(t, LEN(t) - k + 1, k)` for `0 <= k <= LEN(t)` —\n  the second identity is exactly why `RIGHT` is not simply `MID` with a negative start.\n- `MIDB` is the byte-counting sibling. Microsoft documents both on the same page and the\n  Handbook splits them into two entries; see [MIDB](FUNC.MIDB.md).\n- `REPLACE` is the positional counterpart in the other direction: `MID` reads out a window by\n  position, `REPLACE` writes over a window by position, with the same\n  `(start_num, num_chars)` addressing.\n- `TEXTBEFORE`, `TEXTAFTER` and `TEXTSPLIT` are the modern delimiter-based way to do what\n  `MID(…, SEARCH(…), …)` formulas were traditionally written to do. `MID` is not superseded —\n  positional slicing is still its own job — but a formula that computes `start_num` from a\n  `SEARCH` result is usually clearer written with the newer functions.\n\n\n",
    "how-to-implement": "\n### Notes for implementers\n\n\nThe `start_num < 1` rule is the trap. It is tempting to saturate the window at both ends\nsymmetrically, which silently turns `MID(t, 0, 3)` into a two-character result instead of the\ndocumented `#VALUE!`. Clamp the end; validate the start.\n\nCounting in UTF-16 code units rather than Unicode scalar values is not an implementation\nconvenience, it is the specified unit: an implementation that counts scalar values will\ndisagree with Excel on any string containing an astral character, and will disagree in a way\nthat only shows up on emoji and rarer CJK.\n\n\n",
    "quirks": "\n### Result and edge cases\n\n\nReturns `Text`.\n\nThe boundary behaviours Microsoft documents on the `MID` page:\n\n- `start_num` greater than the length of `text` → the empty string `\"\"`, not an error.\n- `start_num` within `text` but `start_num + num_chars` running past the end → the characters\n  from `start_num` to the end of `text`.\n- `num_chars` of zero → the empty string.\n\nEmpty, missing and error arguments follow the shared call model rather than any `MID`-specific\nrule; see [The call pipeline](../model/03-call-pipeline.md) and\n[Coercion and lifting](../model/02-coercion-and-lifting.md). An error value arriving in any\nargument propagates.\n\n\n### Errors\n\n\nAs documented on Microsoft's `MID` page:\n\n| Error | Condition |\n|---|---|\n| `#VALUE!` | `start_num` is less than 1. |\n| `#VALUE!` | `num_chars` is negative. |\n\nBeyond those two, `#VALUE!` is also the expected result of a non-numeric-text value in a\nnumeric argument slot under the shared coercion rules, and any error value passed in\npropagates. The Handbook has not verified the error surface against Excel.\n\n\n",
    "sources": "- Microsoft, \"MID, MIDB functions\" —\n  <https://support.microsoft.com/en-us/office/mid-function-d5f9e25c-d7d6-472e-b568-4ecb12433028>\n  (the documented signature and the four boundary rules quoted above).\n- Handbook, [The value universe](../model/01-value-universe.md) — text as UTF-16 code units,\n  the 32,767-unit cap, and the surrogate-splitting note.\n- Handbook, [Coercion and lifting](../model/02-coercion-and-lifting.md) — to-number coercion of\n  the numeric argument slots and error propagation.\n- Handbook, [The call pipeline](../model/03-call-pipeline.md) — argument preparation and\n  result publication.\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`MID(text, start_num, num_chars)` returns the contiguous run of `num_chars` characters of\n`text` beginning at position `start_num`, where positions are counted from 1 at the first\ncharacter.\n\nWritten against the character positions of `text`, with `n = LEN(text)`:\n\n```\nMID(text, s, k)  =  characters at positions s, s+1, …, min(s + k - 1, n)\n```\n\nand the empty string when `s > n`. Note what the clamp does and does not do: the **end** of the\nwindow is clamped to the end of `text`, so asking for more characters than remain is legal and\nsimply yields the tail. The **start** is not clamped, so `s < 1` is not \"start at the\nbeginning\" — it is an error (see Errors).\n\n\"Character\" here means one UTF-16 code unit, the unit the Handbook's value universe uses for\nworksheet text — the same unit `LEN` counts. A character outside the Basic Multilingual Plane\noccupies two code units, so `MID` can in principle cut a surrogate pair in half. See\n[The value universe](../model/01-value-universe.md), \"Text, exactly\".\n\n\n\n### Arguments\n\n\n| Argument | Meaning |\n|---|---|\n| `text` | The string to slice. Required. |\n| `start_num` | 1-based position of the first character to take. Required. |\n| `num_chars` | How many characters to take. Required, and must not be negative. |\n\nAll three arguments are required — `num_chars` has no default, unlike the optional second\nargument of `LEFT` and `RIGHT`. This is the position where the family is least uniform, and it\nis a frequent source of confusion: `RIGHT(a)` is legal and means one character, `MID(a, 2)` is\nnot legal at all.\n\n`start_num` and `num_chars` are numeric arguments, so ordinary to-number coercion applies to\nwhatever arrives in those slots (a logical, numeric text, a referenced number). The general\nrules are in [Coercion and lifting](../model/02-coercion-and-lifting.md); nothing about them is\nspecific to `MID`. Fractional values are the interesting case, and the Handbook has not checked\nhow they are handled here — see \"What has not been checked\".\n\n\n"
  },
  "signature": {
    "display": "MID(text, start_num, num_chars)",
    "parameters": [
      {
        "description": null,
        "name": "text",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "start_num",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "num_chars",
        "optional": false,
        "repeats": false
      }
    ],
    "trailing_repeats": false
  },
  "sources": {
    "metadata": {
      "admission": {
        "label": "implemented",
        "reason": null
      },
      "arity": {
        "max": 3,
        "min": 3
      },
      "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": "Characters from the middle of a text, from a start position for a given length",
        "short_source": "dna-calc-own"
      },
      "docs": {
        "english_description": "Returns a specific number of characters from a text string starting at the position you specify",
        "microsoft_url": "https://support.microsoft.com/en-us/office/mid-function-d5f9e25c-d7d6-472e-b568-4ecb12433028"
      },
      "entry_kind": "built_in_function",
      "localized_family_names": null,
      "localized_names": [
        {
          "locale": "ar-SA",
          "name": "MID"
        },
        {
          "locale": "bg-BG",
          "name": "MID"
        },
        {
          "locale": "cs-CZ",
          "name": "ČÁST"
        },
        {
          "locale": "da-DK",
          "name": "MIDT"
        },
        {
          "locale": "de-DE",
          "name": "MID"
        },
        {
          "locale": "el-GR",
          "name": "MID"
        },
        {
          "locale": "en-AU",
          "name": "MID"
        },
        {
          "locale": "en-GB",
          "name": "MID"
        },
        {
          "locale": "en-US",
          "name": "MID"
        },
        {
          "locale": "es-ES",
          "name": "EXTRAE"
        },
        {
          "locale": "et-EE",
          "name": "MID"
        },
        {
          "locale": "fi-FI",
          "name": "POIMI.TEKSTI"
        },
        {
          "locale": "fr-FR",
          "name": "STXT"
        },
        {
          "locale": "he-IL",
          "name": "MID"
        },
        {
          "locale": "hr-HR",
          "name": "MID"
        },
        {
          "locale": "hu-HU",
          "name": "KÖZÉP"
        },
        {
          "locale": "id-ID",
          "name": "MID"
        },
        {
          "locale": "it-IT",
          "name": "MID"
        },
        {
          "locale": "ja-JP",
          "name": "MID"
        },
        {
          "locale": "ko-KR",
          "name": "MID"
        },
        {
          "locale": "lt-LT",
          "name": "MID"
        },
        {
          "locale": "lv-LV",
          "name": "MID"
        },
        {
          "locale": "nb-NO",
          "name": "MID"
        },
        {
          "locale": "nl-NL",
          "name": "DEEL"
        },
        {
          "locale": "pl-PL",
          "name": "FRAGMENT.TEKSTU"
        },
        {
          "locale": "pt-BR",
          "name": "MID"
        },
        {
          "locale": "pt-PT",
          "name": "SEG.TEXTO"
        },
        {
          "locale": "ro-RO",
          "name": "MID"
        },
        {
          "locale": "ru-RU",
          "name": "ПСТР"
        },
        {
          "locale": "sk-SK",
          "name": "MID"
        },
        {
          "locale": "sl-SI",
          "name": "MID"
        },
        {
          "locale": "sr-Latn-RS",
          "name": "MID"
        },
        {
          "locale": "sv-SE",
          "name": "EXTEXT"
        },
        {
          "locale": "th-TH",
          "name": "MID"
        },
        {
          "locale": "tr-TR",
          "name": "PARÇAAL"
        },
        {
          "locale": "uk-UA",
          "name": "MID"
        },
        {
          "locale": "vi-VN",
          "name": "MID"
        },
        {
          "locale": "zh-CN",
          "name": "MID"
        },
        {
          "locale": "zh-HK",
          "name": "MID"
        },
        {
          "locale": "zh-TW",
          "name": "MID"
        }
      ],
      "signature": {
        "display": "MID(text, start_num, num_chars)",
        "parameters": [
          {
            "description": null,
            "name": "text",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "start_num",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "num_chars",
            "optional": false,
            "repeats": false
          }
        ],
        "trailing_repeats": false
      },
      "surface_name": "MID",
      "version_marker": null,
      "xlcall": null
    },
    "microsoft": "https://support.microsoft.com/en-us/office/mid-function-d5f9e25c-d7d6-472e-b568-4ecb12433028"
  },
  "try_it": {
    "formula": "=MID(\"handbook\",2,3)"
  },
  "url": "https://handbook.dnacalc.com/functions/MID.html",
  "variants": [
    {
      "code": "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/text_functions.rs#L271-L271",
      "difference": "A surrogate pair counts as two characters.",
      "error_bound": null,
      "evidence": [
        {
          "commit": "",
          "locator": "",
          "note": "",
          "path": "https://support.microsoft.com/en-gb/excel/compatibility-versions",
          "repository": ""
        }
      ],
      "key": {
        "cpu": "Any",
        "excel_build_range": "Compatibility Version 1, all Excel versions"
      },
      "kind": "environment",
      "name": "MID at Compatibility Version 1",
      "onecalc_udf": null,
      "state": "selected",
      "state_summary": "Implemented; selected by the workbook's Compatibility Version."
    },
    {
      "code": "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/text_functions.rs#L271-L271",
      "difference": "A surrogate pair counts as one character. Characters combined from several code points still count separately.",
      "error_bound": null,
      "evidence": [
        {
          "commit": "",
          "locator": "",
          "note": "",
          "path": "https://support.microsoft.com/en-gb/excel/compatibility-versions",
          "repository": ""
        }
      ],
      "key": {
        "cpu": "Any",
        "excel_build_range": "Compatibility Version 2, Excel for Microsoft 365"
      },
      "kind": "environment",
      "name": "MID at Compatibility Version 2",
      "onecalc_udf": null,
      "state": "selected",
      "state_summary": "Implemented; selected by the workbook's Compatibility Version."
    }
  ],
  "versions": []
}