ClosedXML / ClosedXML/ClosedXML.Parser

ToR1C1 emits negative offsets with culture NegativeSign (U+2212); ToA1 can't parse them — R1C1 round-trip fails under sv-SE/fi-FI/nb-NO

Open
#30 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
C#
Stars
14
Forks
8
PR merge metrics
No merged PRs in 30d

Description

## Summary

`FormulaConverter.ToR1C1` serialises negative relative offsets using the current thread culture's `NumberFormat.NegativeSign`. Under cultures whose negative sign is the Unicode MINUS SIGN `U+2212` (sv-SE, fi-FI, nb-NO, …), it emits e.g. `RC[−1]` using `U+2212`. The R1C1 reader (`ToA1` → `CellFormulaR1C1`), however, only accepts the ASCII hyphen-minus `-` (`U+002D`), so it can't parse the string the writer just produced — the round-trip throws `ParsingException`.

## Minimal repro (ClosedXML.Parser 2.0.0)

```csharp
using System.Globalization;
using System.Threading;
using ClosedXML.Parser;

Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("sv-SE"); // NegativeSign = U+2212

// R1C1 form of "=A1/B1" stored in cell C1:
string r1c1 = FormulaConverter.ToR1C1("A1/B1", row: 1, col: 3);
// => "RC[−2]/RC[−1]" (the offsets use U+2212, not ASCII '-')

string a1 = FormulaConverter.ToA1(r1c1, row: 1, col: 3);
// throws ClosedXML.Parser.ParsingException:
// The formula `RC[−2]/RC[−1]` wasn't parsed correctly.
// The expression `RC` was parsed, but the rest `[−2]/RC[−1]` wasn't.
```

Under `en-US` / `InvariantCulture` the same code emits `RC[-2]/RC[-1]` with ASCII `-` and round-trips fine.

## Current vs expected

- **Current:** the R1C1 writer's output is culture-dependent and is not always re-readable by the R1C1 reader.
- **Expected:** R1C1 offsets are a serialization/machine format, so the writer should emit the invariant ASCII `-` regardless of thread culture (and/or the reader should accept `U+2212`). Either one makes the round-trip culture-independent.

## Real-world impact (via ClosedXML 0.105.0)

This surfaces when simply *loading* a workbook. ClosedXML expands shared formulas at load by converting the master to R1C1 and back to A1 per dependent cell, so loading any `.xlsx` containing a shared formula with a negative relative reference (e.g. `=B2-A2` filled down a column — very common) throws on a thread whose culture uses `U+2212`:

```
ClosedXML.Parser.ParsingException: The formula `RC[−2]/RC[−1]` wasn't parsed correctly...
at ClosedXML.Parser.FormulaConverter.ToA1(String formulaR1C1, Int32 row, Int32 col)
at ClosedXML.Excel.XLWorkbook.SetCellFormula(...)
at ClosedXML.Excel.XLWorkbook.LoadCell(...)
...
at ClosedXML.Excel.XLWorkbook..ctor(Stream stream)
```

## Environment

- ClosedXML.Parser 2.0.0 (didn't spot a related fix on `main`, though it looks mid-rewrite for 3.0)
- Reproduced through ClosedXML 0.105.0
- .NET 10
- Affected cultures: any whose `NumberFormat.NegativeSign` is `U+2212` — e.g. sv-SE, fi-FI, nb-NO

Happy to open a PR if a fix direction is welcome — my guess is emitting the invariant `-` in the R1C1 reference writer is the smaller change.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.