Reject Unicode noncharacters in UNICHAR

This commit is contained in:
Harrison Booth
2026-10-30 19:24:46 -05:00
parent 1f4c67ef0a
commit 4d725e6bc1
2 changed files with 15 additions and 2 deletions
+12 -1
View File
@@ -281,7 +281,11 @@ fn unichar(a: &[Arg], _c: &mut dyn Ctx) -> R<Value> {
if !(1.0..=1_114_111.0).contains(&n) {
return Err(CellError::Value);
}
match char::from_u32(n as u32) {
let cp = n as u32;
if (0xFDD0..=0xFDEF).contains(&cp) || cp & 0xFFFE == 0xFFFE {
return Err(CellError::NA);
}
match char::from_u32(cp) {
Some(c) => text_val(c.to_string()),
None => Err(CellError::NA),
}
@@ -1181,8 +1185,15 @@ mod tests {
close(ev("CODE", vec![t("€")]), 128.0);
is_err(ev("CODE", vec![t("")]), CellError::Value);
is_text(ev("UNICHAR", vec![n(9731.0)]), "☃");
for cp in [0xFDD0, 0xFDEF, 0xFFFE, 0xFFFF, 0x1FFFE, 0x1FFFF, 0x10FFFE, 0x10FFFF] {
is_err(ev("UNICHAR", vec![n(f64::from(cp))]), CellError::NA);
}
for cp in [0xFDCF, 0xFDF0, 0xFFFD, 0x1FFFD] {
assert!(matches!(ev("UNICHAR", vec![n(f64::from(cp))]), Value::Text(_)));
}
close(ev("UNICODE", vec![t("☃")]), 9731.0);
is_err(ev("UNICHAR", vec![n(0.0)]), CellError::Value);
is_err(ev("UNICHAR", vec![n(1_114_112.0)]), CellError::Value);
is_err(ev("UNICHAR", vec![n(55296.0)]), CellError::NA);
}
+3 -1
View File
@@ -1,6 +1,6 @@
# Function parity: worksheet functions and formulas
> **Last reviewed:** 2026-10-15 · **Last updated:** 2026-10-27 · **Change:** minor (ECMA.CEILING listed with USDOLLAR as not on Microsoft's list; earlier: IMSQRT reproduces the stray real part Excel gives for negative reals, and the other IM* differences from Excel are listed; earlier: the LAMBDA row lists the recursion limit and its `#NUM!`, and the error a defined name holding an error gives when called; earlier: number text with accounting parentheses coerces like Excel 365; INDEX with one index on a 2-D reference is #REF! as in Excel; earlier: SUBTOTAL and AGGREGATE cap the cells they visit, #2175) · **Target:** Microsoft Excel (Microsoft 365), Excel for Mac 16.113.4
> **Last reviewed:** 2026-10-31 · **Last updated:** 2026-10-31 · **Change:** minor (UNICHAR returns `#N/A` for Unicode noncharacters, as observed in Excel; earlier: ECMA.CEILING listed with USDOLLAR as not on Microsoft's list; IMSQRT reproduces Excel's stray real part for negative reals) · **Target:** Microsoft Excel (Microsoft 365), Excel for Mac 16.113.4
Excel's worksheet functions, category by category, against GridCraft's function library. Part of
[target-app-parity.md](target-app-parity.md); gaps feed [gaps.md](gaps.md).
@@ -29,6 +29,8 @@ Excel's worksheet functions, category by category, against GridCraft's function
## Coverage
| 2026-10-31 | minor | UNICHAR returns `#N/A` for U+FDD0–U+FDEF and U+FFFE/U+FFFF on every plane; adjacent valid characters and existing invalid-range/surrogate errors remain unchanged, matching Excel |
**Measured: 513 / 523 by name (98.1%); 504 / 523 working (96.4%).**
| Category | Excel | Ours | Working | % working | Missing |