{
  "category": "Text functions",
  "display_name": "PROPER",
  "entry_kind": "built_in_function",
  "eval_api": {
    "method": "POST",
    "url": "https://handbook.dnacalc.com/api/eval"
  },
  "function_id": "FUNC.PROPER",
  "implementation_state": {
    "answer_bank": {
      "excel_builds": [
        "20527"
      ],
      "larger_numeric": 0,
      "last_bit": 0,
      "matched": 3,
      "other_mismatch": 0,
      "refused": 0,
      "rows": 3,
      "unread": 0,
      "worst_ulp": 0
    },
    "detail": "Recorded: 3 in the answer bank and 5 workbook cells.",
    "dnacalc_commit": "9e1884369a678158dd82d3d74188daf986995e87",
    "in_catalogue": true,
    "state": "matches",
    "state_label": "Matches every recorded Excel answer",
    "summary": "Matches all 8 recorded answers",
    "workbook_corpus": {
      "cells": 5,
      "matched": 5
    }
  },
  "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#L282-L282",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/ported/text_kernels.rs#L505-L508",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/ported/text_kernels.rs#L554-L577"
      ],
      "repository": "https://github.com/DnaCalc/DnaCalc",
      "shared_code": [
        "catalogue/text_functions::cased",
        "ported/text_kernels::text",
        "ported/text_kernels::text_from_str",
        "ported/text_kernels::push_singleton_or_original",
        "ported/text_kernels::push_upper",
        "ported/text_kernels::push_lower",
        "ported/text_kernels::is_well_formed"
      ],
      "source": "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/text_functions.rs#L282-L282",
      "state": "matches",
      "suite": null,
      "summary": "Matches all 8 recorded answers"
    }
  ],
  "json_url": "https://handbook.dnacalc.com/api/functions/FUNC.PROPER.json",
  "name": "PROPER",
  "notes": [
    {
      "basis": "6 recorded LOWER and 4 recorded PROPER readings, in a workbook at compatibility version 2.",
      "documentation": null,
      "evidence": [
        {
          "commit": "ae13ca181bc1d5e3c9e266f26a856ba634707d8e",
          "locator": null,
          "note": "recorded answers pinned",
          "path": "apps/dna-onecalc/tests/acceptance.rs",
          "repository": "DnaCalc"
        },
        {
          "commit": "2d0eddcac86413014643af81d646581d54ba57bc",
          "locator": null,
          "note": "6 recorded readings",
          "path": "crates/calc-func/tests/captures/fn3_questions/LOWER.reading.json",
          "repository": "DnaCalc"
        },
        {
          "commit": "2d0eddcac86413014643af81d646581d54ba57bc",
          "locator": null,
          "note": "4 recorded readings",
          "path": "crates/calc-func/tests/captures/fn3_questions/PROPER.reading.json",
          "repository": "DnaCalc"
        }
      ],
      "functions": [
        "FUNC.LOWER",
        "FUNC.PROPER"
      ],
      "inferred": "The readings cover one Deseret letter and two combining marks. That every letter above U+FFFF and every mark behave the same is inferred.",
      "kind": "quirk",
      "note_id": "FN-LOWER-001",
      "open": [
        "Behaviour at compatibility version 1 has not been read for these inputs."
      ],
      "recorded_on": "2026-11-04",
      "repros": [
        {
          "call": "LOWER(A1)",
          "correct": null,
          "excel": {
            "bits": null,
            "display": "𐐀",
            "kind": "text"
          },
          "input_route": "cell-value2",
          "inputs": [
            {
              "name": "text",
              "value": {
                "bits": null,
                "display": "𐐀",
                "kind": "text"
              }
            }
          ],
          "recorded_in": "Excel 16.0.20527.20088, Windows 64-bit, AMD Ryzen 7 4800H, workbook compatibility version 2",
          "source": {
            "commit": "2d0eddcac86413014643af81d646581d54ba57bc",
            "locator": "fn3-lower-001",
            "note": null,
            "path": "crates/calc-func/tests/captures/fn3_questions/LOWER.reading.json",
            "repository": "DnaCalc"
          }
        },
        {
          "call": "LOWER(A1)",
          "correct": null,
          "excel": {
            "bits": null,
            "display": "a𐐀ς",
            "kind": "text"
          },
          "input_route": "cell-value2",
          "inputs": [
            {
              "name": "text",
              "value": {
                "bits": null,
                "display": "A𐐀Σ",
                "kind": "text"
              }
            }
          ],
          "recorded_in": "Excel 16.0.20527.20088, Windows 64-bit, AMD Ryzen 7 4800H, workbook compatibility version 2",
          "source": {
            "commit": "2d0eddcac86413014643af81d646581d54ba57bc",
            "locator": "fn3-lower-003",
            "note": null,
            "path": "crates/calc-func/tests/captures/fn3_questions/LOWER.reading.json",
            "repository": "DnaCalc"
          }
        },
        {
          "call": "LOWER(A1)",
          "correct": null,
          "excel": {
            "bits": null,
            "display": "ασ̀",
            "kind": "text"
          },
          "input_route": "cell-value2",
          "inputs": [
            {
              "name": "text",
              "value": {
                "bits": null,
                "display": "ΑΣ̀",
                "kind": "text"
              }
            }
          ],
          "recorded_in": "Excel 16.0.20527.20088, Windows 64-bit, AMD Ryzen 7 4800H, workbook compatibility version 2",
          "source": {
            "commit": "2d0eddcac86413014643af81d646581d54ba57bc",
            "locator": "fn3-lower-004",
            "note": null,
            "path": "crates/calc-func/tests/captures/fn3_questions/LOWER.reading.json",
            "repository": "DnaCalc"
          }
        },
        {
          "call": "LOWER(A1)",
          "correct": null,
          "excel": {
            "bits": null,
            "display": "ας.",
            "kind": "text"
          },
          "input_route": "cell-value2",
          "inputs": [
            {
              "name": "text",
              "value": {
                "bits": null,
                "display": "ΑΣ.",
                "kind": "text"
              }
            }
          ],
          "recorded_in": "Excel 16.0.20527.20088, Windows 64-bit, AMD Ryzen 7 4800H, workbook compatibility version 2",
          "source": {
            "commit": "2d0eddcac86413014643af81d646581d54ba57bc",
            "locator": "fn3-lower-005",
            "note": null,
            "path": "crates/calc-func/tests/captures/fn3_questions/LOWER.reading.json",
            "repository": "DnaCalc"
          }
        },
        {
          "call": "PROPER(A1)",
          "correct": null,
          "excel": {
            "bits": null,
            "display": "A𐐀B",
            "kind": "text"
          },
          "input_route": "cell-value2",
          "inputs": [
            {
              "name": "text",
              "value": {
                "bits": null,
                "display": "a𐐀b",
                "kind": "text"
              }
            }
          ],
          "recorded_in": "Excel 16.0.20527.20088, Windows 64-bit, AMD Ryzen 7 4800H, workbook compatibility version 2",
          "source": {
            "commit": "2d0eddcac86413014643af81d646581d54ba57bc",
            "locator": "fn3-proper-002",
            "note": null,
            "path": "crates/calc-func/tests/captures/fn3_questions/PROPER.reading.json",
            "repository": "DnaCalc"
          }
        },
        {
          "call": "PROPER(A1)",
          "correct": null,
          "excel": {
            "bits": null,
            "display": "Aσ́",
            "kind": "text"
          },
          "input_route": "cell-value2",
          "inputs": [
            {
              "name": "text",
              "value": {
                "bits": null,
                "display": "aΣ́",
                "kind": "text"
              }
            }
          ],
          "recorded_in": "Excel 16.0.20527.20088, Windows 64-bit, AMD Ryzen 7 4800H, workbook compatibility version 2",
          "source": {
            "commit": "2d0eddcac86413014643af81d646581d54ba57bc",
            "locator": "fn3-proper-004",
            "note": null,
            "path": "crates/calc-func/tests/captures/fn3_questions/PROPER.reading.json",
            "repository": "DnaCalc"
          }
        }
      ],
      "schema": "efh.function-note/v1",
      "statement": "LOWER did not change the Deseret capital U+10400, a cased letter above U+FFFF, either alone or inside other text: LOWER(\"A𐐀Σ\") is \"a𐐀ς\", where the Greek capital sigma at the end becomes the final form. Greek sigma depends on what follows: followed by a full stop it takes the final form ς, and followed by a combining mark, U+0300 or U+0301, it takes the medial form σ. PROPER treats a character above U+FFFF as a word boundary, so PROPER(\"a𐐀b\") is \"A𐐀B\", with the B capitalised and the Deseret letter unchanged.",
      "status": "measured",
      "title": "LOWER leaves letters above U+FFFF alone, and a combining mark stops the final sigma"
    }
  ],
  "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- **`UPPER` and `LOWER`** are the unconditional case transforms. All three lowercase by\n  default; `PROPER` differs only in which characters it raises back up.\n- **`TEXTSPLIT` / `TEXTBEFORE` / `TEXTAFTER`** are what you actually want if the task is\n  \"capitalize each word\" with a definition of \"word\" that is not \"run of letters\" — `PROPER`\n  cannot be configured, so word-level work has to be done around it.\n- There is no compatibility-replacement pair here: `PROPER` is neither superseded nor a\n  retained legacy name.\n- Readers confuse `PROPER` with `TRIM`, because both are reached for while cleaning imported\n  names. They share no behaviour: `TRIM` deals in spaces, `PROPER` in case.\n\n\n",
    "how-to-implement": "\n### Notes for implementers\n\n\nThe whole function is a one-pass scan with one bit of state (was the previous character a\nletter?), so the interest is entirely in the character classification.\n\nThree decisions have to be made, and Microsoft's documentation makes none of them:\n\n1. **What \"is a letter\" means.** ASCII `A-Za-z`, the Unicode `L*` general categories, and the\n   host code page's letter table are three different answers, and they differ on accented\n   characters, on the Latin Extended blocks, and on modifier letters.\n2. **What case mapping is applied.** Simple per-character mapping and full case mapping\n   disagree — `ß` uppercases to `SS` under full mapping, which changes the string's length.\n3. **Whether the mapping is locale-sensitive.** Turkish `i`/`İ` is the standing example. A\n   locale-invariant mapping is the safer default but is a decision, not a neutral choice.\n\nRecord whichever you pick as unverified. All three are the sort of thing that silently agrees\nwith Excel on English data and silently disagrees on everything else.\n\n\n",
    "quirks": "\n### Result and edge cases\n\n\nReturns `Text`.\n\n- Empty `text` returns the empty string.\n- Non-letter characters pass through unchanged; only letters are rewritten.\n- Numbers and logicals arriving in the argument slot are converted to text first under the\n  shared coercion rules, then processed — see\n  [Coercion and lifting](../model/02-coercion-and-lifting.md). What the resulting text looks\n  like for a number is a to-text question, not a `PROPER` question, and the shared chapter is\n  explicit that to-text behaviour is only outlined, not pinned.\n- Error values propagate.\n\n\n### Errors\n\n\nMicrosoft's `PROPER` page documents no error conditions of its own. The errors reachable here\nare the shared ones: an error value in the argument propagates, and a value that cannot be\nconverted to text surfaces `#VALUE!` under the shared coercion rules. The Handbook has not\nverified either against Excel.\n\n\n",
    "sources": "\n- Microsoft, \"PROPER function\" —\n  <https://support.microsoft.com/en-us/office/proper-function-52a5a283-e8b2-49be-8506-b2887b889f94>\n  (the capitalize-after-non-letter rule and the lowercase-everything-else rule).\n- Handbook, [Coercion and lifting](../model/02-coercion-and-lifting.md) — to-text conversion of\n  non-text arguments, stated there as outline-level rather than pinned.\n- Handbook, [The value universe](../model/01-value-universe.md) — worksheet text as UTF-16\n  code units.\n- Handbook projections `data/functions/FUNC.PROPER.json` (placeholder signature) and\n  `data/presence/FUNC.PROPER.json` (implementing module; `BUG-FUNC-008`, `BUG-FUNC-016`).\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`PROPER(text)` rewrites the case of every letter in `text` according to one rule, applied\ncharacter by character:\n\n> A letter is uppercased if it is the first character of `text` or if the character before it\n> is **not a letter**. Every other letter is lowercased.\n\nThat is Microsoft's documented rule, and reading it literally is the whole story — because\nwhat it says is *not* \"capitalize each word\". It says \"capitalize after any non-letter\". The\ntwo descriptions diverge constantly, and the divergences are the reason this function has a\nreputation:\n\n| Input | Result under the documented rule |\n|---|---|\n| `\"o'brien\"` | `O'Brien` — the apostrophe is not a letter |\n| `\"2nd place\"` | `2Nd Place` — the digit is not a letter |\n| `\"e-mail\"` | `E-Mail` |\n| `\"McDonald\"` | `Mcdonald` — the interior capital is lowercased |\n| `\"IBM\"` | `Ibm` |\n\nNone of these is a bug. All five follow from one rule with no word list, no dictionary, and no\nexceptions. `PROPER` is a character classifier, not a name formatter, and it should not be\nused as one.\n\nThe rule is also **unconditional on the rest of the string**: `PROPER` lowercases letters it\ndid not capitalize, so it destroys existing casing rather than preserving it. This is what\nseparates it from a \"capitalize first letters\" transformation.\n\n\n\n### Arguments\n\n\n| Argument | Meaning |\n|---|---|\n| `text` | The string whose case is rewritten. Required, and the only argument. |\n\n"
  },
  "signature": {
    "display": "PROPER(text)",
    "parameters": [
      {
        "description": null,
        "name": "text",
        "optional": false,
        "repeats": false
      }
    ],
    "trailing_repeats": false
  },
  "sources": {
    "metadata": {
      "admission": {
        "label": "implemented",
        "reason": null
      },
      "arity": {
        "max": 1,
        "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": "Text with the first letter of each word in upper case and the rest in lower case",
        "short_source": "dna-calc-own"
      },
      "docs": {
        "english_description": "Capitalizes the first letter in each word of a text value",
        "microsoft_url": "https://support.microsoft.com/en-us/office/proper-function-52a5a283-e8b2-49be-8506-b2887b889f94"
      },
      "entry_kind": "built_in_function",
      "localized_family_names": null,
      "localized_names": [
        {
          "locale": "ar-SA",
          "name": "PROPER"
        },
        {
          "locale": "bg-BG",
          "name": "PROPER"
        },
        {
          "locale": "cs-CZ",
          "name": "VELKÁ2"
        },
        {
          "locale": "da-DK",
          "name": "STORT.FORBOGSTAV"
        },
        {
          "locale": "de-DE",
          "name": "GROSS2"
        },
        {
          "locale": "el-GR",
          "name": "PROPER"
        },
        {
          "locale": "en-AU",
          "name": "PROPER"
        },
        {
          "locale": "en-GB",
          "name": "PROPER"
        },
        {
          "locale": "en-US",
          "name": "PROPER"
        },
        {
          "locale": "es-ES",
          "name": "NOMPROPIO"
        },
        {
          "locale": "et-EE",
          "name": "PROPER"
        },
        {
          "locale": "fi-FI",
          "name": "ERISNIMI"
        },
        {
          "locale": "fr-FR",
          "name": "NOMPROPRE"
        },
        {
          "locale": "he-IL",
          "name": "PROPER"
        },
        {
          "locale": "hr-HR",
          "name": "PROPER"
        },
        {
          "locale": "hu-HU",
          "name": "TNÉV"
        },
        {
          "locale": "id-ID",
          "name": "PROPER"
        },
        {
          "locale": "it-IT",
          "name": "MAIUSC.INIZ"
        },
        {
          "locale": "ja-JP",
          "name": "PROPER"
        },
        {
          "locale": "ko-KR",
          "name": "PROPER"
        },
        {
          "locale": "lt-LT",
          "name": "PROPER"
        },
        {
          "locale": "lv-LV",
          "name": "PROPER"
        },
        {
          "locale": "nb-NO",
          "name": "STOR.FORBOKSTAV"
        },
        {
          "locale": "nl-NL",
          "name": "BEGINLETTERS"
        },
        {
          "locale": "pl-PL",
          "name": "Z.WIELKIEJ.LITERY"
        },
        {
          "locale": "pt-BR",
          "name": "PRI.MAIÚSCULA"
        },
        {
          "locale": "pt-PT",
          "name": "INICIAL.MAIÚSCULA"
        },
        {
          "locale": "ro-RO",
          "name": "PROPER"
        },
        {
          "locale": "ru-RU",
          "name": "ПРОПНАЧ"
        },
        {
          "locale": "sk-SK",
          "name": "PROPER"
        },
        {
          "locale": "sl-SI",
          "name": "PROPER"
        },
        {
          "locale": "sr-Latn-RS",
          "name": "PROPER"
        },
        {
          "locale": "sv-SE",
          "name": "INITIAL"
        },
        {
          "locale": "th-TH",
          "name": "PROPER"
        },
        {
          "locale": "tr-TR",
          "name": "YAZIM.DÜZENİ işlevi"
        },
        {
          "locale": "uk-UA",
          "name": "PROPER"
        },
        {
          "locale": "vi-VN",
          "name": "PROPER"
        },
        {
          "locale": "zh-CN",
          "name": "PROPER"
        },
        {
          "locale": "zh-HK",
          "name": "PROPER"
        },
        {
          "locale": "zh-TW",
          "name": "PROPER"
        }
      ],
      "signature": {
        "display": "PROPER(text)",
        "parameters": [
          {
            "description": null,
            "name": "text",
            "optional": false,
            "repeats": false
          }
        ],
        "trailing_repeats": false
      },
      "surface_name": "PROPER",
      "version_marker": null,
      "xlcall": {
        "code": "114",
        "symbol": "xlfProper"
      }
    },
    "microsoft": "https://support.microsoft.com/en-us/office/proper-function-52a5a283-e8b2-49be-8506-b2887b889f94"
  },
  "try_it": {
    "formula": "=PROPER(\"o'brien 2nd e-mail\")"
  },
  "url": "https://handbook.dnacalc.com/functions/PROPER.html",
  "variants": [],
  "versions": [
    {
      "behaviour": "PROPER(A1) returned A𐐀B. PROPER(A1) returned Aσ́. Inputs were supplied through cells using Value2. These are controls from this environment, not a same-input comparison with another build.",
      "excel_build": "16.0.20527.20088",
      "observations": [
        {
          "call": "PROPER(A1)",
          "excel": {
            "bits": null,
            "display": "A𐐀B",
            "kind": "text"
          },
          "input_route": "cell-value2",
          "inputs": [
            {
              "name": "text",
              "value": {
                "bits": null,
                "display": "a𐐀b",
                "kind": "text"
              }
            }
          ],
          "recorded_in": "Excel 16.0.20527.20088, Windows 64-bit, AMD Ryzen 7 4800H, workbook compatibility version 2"
        },
        {
          "call": "PROPER(A1)",
          "excel": {
            "bits": null,
            "display": "Aσ́",
            "kind": "text"
          },
          "input_route": "cell-value2",
          "inputs": [
            {
              "name": "text",
              "value": {
                "bits": null,
                "display": "aΣ́",
                "kind": "text"
              }
            }
          ],
          "recorded_in": "Excel 16.0.20527.20088, Windows 64-bit, AMD Ryzen 7 4800H, workbook compatibility version 2"
        }
      ],
      "platform": "Windows 64-bit, AMD Ryzen 7 4800H, workbook compatibility version 2",
      "sources": [
        "https://github.com/DnaCalc/ExcelFunctionsHandbook/blob/3345a87/content/notes/FN-LOWER-001.json"
      ]
    }
  ]
}