{
  "category": "Text functions",
  "display_name": "LEFT",
  "entry_kind": "built_in_function",
  "eval_api": {
    "method": "POST",
    "url": "https://handbook.dnacalc.com/api/eval"
  },
  "function_id": "FUNC.LEFT",
  "implementation_state": {
    "answer_bank": null,
    "detail": "Recorded: 17 workbook cells.",
    "dnacalc_commit": "9e1884369a678158dd82d3d74188daf986995e87",
    "in_catalogue": true,
    "state": "matches",
    "state_label": "Matches every recorded Excel answer",
    "summary": "Matches all 17 recorded answers",
    "workbook_corpus": {
      "cells": 17,
      "matched": 17
    }
  },
  "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#L269-L269"
      ],
      "repository": "https://github.com/DnaCalc/DnaCalc",
      "shared_code": [
        "catalogue/text_functions::side_count",
        "catalogue/text_functions::left",
        "ported/text_kernels::text",
        "ported/text_kernels::text_from_str",
        "ported/text_kernels::date_integer_floor",
        "ported/text_kernels::nonnegative_count",
        "ported/text_kernels::unit_width",
        "ported/text_kernels::character_boundary",
        "ported/text_kernels::slice_character_count",
        "ported/text_kernels::character_scan_end",
        "ported/text_kernels::len_character_count",
        "ported/text_kernels::take_left",
        "ported/text_kernels::truncated",
        "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#L269-L269",
      "state": "matches",
      "suite": null,
      "summary": "Matches all 17 recorded answers"
    }
  ],
  "json_url": "https://handbook.dnacalc.com/api/functions/FUNC.LEFT.json",
  "name": "LEFT",
  "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- **`RIGHT`** is the mirror; **`MID`** generalises both with an explicit start position. All\n  three are one family and should share one unit decision.\n- **[`LEN`](FUNC.LEN.md)** supplies the bound: `LEFT(a, LEN(a))` is `a`, and that identity is\n  the cheapest test that the family's unit choices agree.\n- **[`LEFTB`](FUNC.LEFTB.md)** is the byte-counting variant, documented in the same Microsoft\n  article and marked there as deprecated.\n- **`TEXTBEFORE`** is the modern delimiter-driven alternative and is usually what a formula\n  written as `LEFT(a, FIND(x,a)-1)` actually wants — including because `TEXTBEFORE` can be told\n  what to do when the delimiter is absent, where the `LEFT`/`FIND` composition simply errors.\n- **`TRIM`** is the usual companion when the slice is being taken from fixed-width imported\n  data.\n\n\n",
    "how-to-implement": "\n### Notes for implementers\n\n1. **Saturate, do not error, on an over-long count.** This is documented behaviour and it is\n   the behaviour that makes the function composable.\n2. **Decide what a fractional count means.** The documentation states a constraint on sign, not\n   on integrality. Truncation toward zero is the natural reading; it is a decision, not a\n   given.\n3. **Slice on the same unit the length function counts in**, and — given the Compatibility\n   Version change — parameterise that unit rather than hard-coding it.\n4. **Never split a surrogate pair silently.** Under a code-unit slicer, `LEFT` on astral text\n   can produce a lone high surrogate, which the value-universe chapter records as a reachable\n   state. Producing it may be correct emulation; producing it *unknowingly* is a defect.\n\n\n",
    "quirks": "\n### Result and edge cases\n\n\nThe return kind is `Text`.\n\n- **Zero count** yields empty text, not an error.\n- **Count beyond the length** yields the whole string, per the article.\n- **Non-text arguments convert first.** `LEFT(1234.5, 2)` slices the *rendering* `1234.5`, so\n  it is `12`. This is the reason `LEFT` is a poor tool for extracting digits from numbers: the\n  rendering, not the value, is what gets cut, and the rendering depends on how the number\n  formats under General.\n- **A negative count** violates the documented constraint. The article states the constraint\n  but does not state the consequence of breaking it; see \"Errors\".\n- Empty cells, omitted arguments and arrays follow the shared call model\n  ([chapter 03](../model/03-call-pipeline.md)).\n\n\n\n### Errors\n\n\nMicrosoft's article states that `num_chars` must be greater than or equal to zero, and does not\nname the error produced when it is not. The Handbook records the constraint as documented and\nthe error value as unverified.\n\nError inputs propagate, and a value kind with no text conversion surfaces `#VALUE!` under the\nshared coercion rules ([chapter 02](../model/02-coercion-and-lifting.md)).\n\n\n",
    "sources": "- Microsoft, \"LEFT function\" —\n  <https://support.microsoft.com/en-us/office/left-function-9203d2d2-7960-479b-84c6-1ea52b99640c>\n  (the first-characters statement; `num_chars` must be ≥ 0, defaults to 1, and returns the\n  whole text when it exceeds the length; the LEFTB deprecation line and the Compatibility\n  Version 2 surrogate note). Retrieved for this page.\n- Handbook `content/model/01-value-universe.md` (UTF-16 code units and the reachable\n  lone-surrogate state) and `content/model/03-call-pipeline.md`.\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`LEFT` returns the first characters of a text string — a prefix of the requested length.\nMicrosoft's article states it as returning the first character or characters in a text string,\nbased on the number of characters you specify.\n\nPrecisely: with `t` the text and `n` the requested count, the result is the first `min(n,\nLEN(t))` characters of `t`. There is no error for asking for more than exists; the article says\nthat if `num_chars` is greater than the length of the text, `LEFT` returns all of the text.\nThat saturating behaviour is what makes `LEFT` usable directly on ragged data without a guard.\n\nThe unit of \"character\" is shared with the rest of the slicing family and is discussed on\n[`LEN`](FUNC.LEN.md), where Microsoft documents a Compatibility Version 2 change to how\nsurrogate pairs are counted. The `LEFT` article carries the corresponding note from the other\nside: it states that `LEFT` now handles Unicode surrogates through the Compatibility Version\nfeature (Version 2). Whatever unit `LEN` counts in, `LEFT` should slice in — but the Handbook\nhas not checked that they move together, and it is the single most consequential unchecked\nquestion about this family.\n\n\n\n### Arguments\n\n\n`text` — required, the text string containing the characters to extract.\n\n`num_chars` — optional. Per the article: it specifies how many characters to extract, it must\nbe greater than or equal to zero, if it exceeds the text length the entire text is returned,\nand it **defaults to 1 if omitted**.\n\nThat default is the argument fact readers most often get wrong, in both directions. `LEFT(a)`\nis not \"the whole string\" and it is not an error; it is the first character. And because the\ndefault is 1 rather than 0, `LEFT` and `MID` do not agree on what an unspecified count means —\n`MID` has no optional count at all.\n\n`num_chars = 0` is explicitly admissible (the documented constraint is \"greater than or equal\nto zero\") and yields empty text.\n\n\n"
  },
  "signature": {
    "display": "LEFT(text, [num_chars])",
    "parameters": [
      {
        "description": null,
        "name": "text",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "num_chars",
        "optional": true,
        "repeats": false
      }
    ],
    "trailing_repeats": false
  },
  "sources": {
    "metadata": {
      "admission": {
        "label": "implemented",
        "reason": null
      },
      "arity": {
        "max": 2,
        "min": 1
      },
      "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": "The first characters of a text",
        "short_source": "dna-calc-own"
      },
      "docs": {
        "english_description": "Returns the leftmost characters from a text value",
        "microsoft_url": "https://support.microsoft.com/en-us/office/left-function-9203d2d2-7960-479b-84c6-1ea52b99640c"
      },
      "entry_kind": "built_in_function",
      "localized_family_names": null,
      "localized_names": [
        {
          "locale": "ar-SA",
          "name": "LEFT"
        },
        {
          "locale": "bg-BG",
          "name": "LEFT"
        },
        {
          "locale": "cs-CZ",
          "name": "ZLEVA"
        },
        {
          "locale": "da-DK",
          "name": "VENSTRE"
        },
        {
          "locale": "de-DE",
          "name": "LEFT"
        },
        {
          "locale": "el-GR",
          "name": "LEFT"
        },
        {
          "locale": "en-AU",
          "name": "LEFT"
        },
        {
          "locale": "en-GB",
          "name": "LEFT"
        },
        {
          "locale": "en-US",
          "name": "LEFT"
        },
        {
          "locale": "es-ES",
          "name": "IZQUIERDA"
        },
        {
          "locale": "et-EE",
          "name": "LEFT"
        },
        {
          "locale": "fi-FI",
          "name": "VASEN"
        },
        {
          "locale": "fr-FR",
          "name": "GAUCHE"
        },
        {
          "locale": "he-IL",
          "name": "LEFT"
        },
        {
          "locale": "hr-HR",
          "name": "LEFT"
        },
        {
          "locale": "hu-HU",
          "name": "BAL"
        },
        {
          "locale": "id-ID",
          "name": "LEFT"
        },
        {
          "locale": "it-IT",
          "name": "LEFT"
        },
        {
          "locale": "ja-JP",
          "name": "LEFT"
        },
        {
          "locale": "ko-KR",
          "name": "LEFT"
        },
        {
          "locale": "lt-LT",
          "name": "LEFT"
        },
        {
          "locale": "lv-LV",
          "name": "LEFT"
        },
        {
          "locale": "nb-NO",
          "name": "LEFT"
        },
        {
          "locale": "nl-NL",
          "name": "LINKS"
        },
        {
          "locale": "pl-PL",
          "name": "LEWY"
        },
        {
          "locale": "pt-BR",
          "name": "LEFT"
        },
        {
          "locale": "pt-PT",
          "name": "ESQUERDA"
        },
        {
          "locale": "ro-RO",
          "name": "LEFT"
        },
        {
          "locale": "ru-RU",
          "name": "ЛЕВСИМВ"
        },
        {
          "locale": "sk-SK",
          "name": "LEFT"
        },
        {
          "locale": "sl-SI",
          "name": "LEFT"
        },
        {
          "locale": "sr-Latn-RS",
          "name": "LEFT"
        },
        {
          "locale": "sv-SE",
          "name": "VÄNSTER"
        },
        {
          "locale": "th-TH",
          "name": "LEFT"
        },
        {
          "locale": "tr-TR",
          "name": "SOLDAN"
        },
        {
          "locale": "uk-UA",
          "name": "LEFT"
        },
        {
          "locale": "vi-VN",
          "name": "LEFT"
        },
        {
          "locale": "zh-CN",
          "name": "LEFT"
        },
        {
          "locale": "zh-HK",
          "name": "LEFT"
        },
        {
          "locale": "zh-TW",
          "name": "LEFT"
        }
      ],
      "signature": {
        "display": "LEFT(text, [num_chars])",
        "parameters": [
          {
            "description": null,
            "name": "text",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "num_chars",
            "optional": true,
            "repeats": false
          }
        ],
        "trailing_repeats": false
      },
      "surface_name": "LEFT",
      "version_marker": null,
      "xlcall": null
    },
    "microsoft": "https://support.microsoft.com/en-us/office/left-function-9203d2d2-7960-479b-84c6-1ea52b99640c"
  },
  "try_it": {
    "formula": "=LEFT(\"handbook\",4)"
  },
  "url": "https://handbook.dnacalc.com/functions/LEFT.html",
  "variants": [],
  "versions": []
}