https://bz.apache.org/ooo/show_bug.cgi?id=128623

[email protected] changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |ms_interoperability,
                   |                            |regression

--- Comment #1 from [email protected] ---
The R1C1 to A1 format conversion needs to convert a 1-based decimal column
number, to a 0-based base 26 (A-Z) column number.

However it's not that simple, if we use "0" to represent an absent leading
digit, then is it really base 26 when:

0A=0
0B=1
...
0Z=25
AA=26
AB=27
...
AZ=52
BA=53
...

Only the right-most digit is base 26, the other digits are more like base 27,
as 000A == 00A == 0A == A, so the "0" must be a 27th value...

In ScColToAlpha() of main/sc/source/core/tool/address.cxx, we do this
conversion using the following C++ code:

---snip---
void ScColToAlpha( rtl::OUStringBuffer& rBuf, SCCOL nCol )
{
    if (nCol < 26*26)
    {
        if (nCol < 26)
            rBuf.append( static_cast<sal_Unicode>( 'A' +
                        static_cast<sal_uInt16>(nCol)));
        else
        {
            rBuf.append( static_cast<sal_Unicode>( 'A' +
                        (static_cast<sal_uInt16>(nCol) / 26) - 1));
            rBuf.append( static_cast<sal_Unicode>( 'A' +
                        (static_cast<sal_uInt16>(nCol) % 26)));
        }
    }
    else
    {
        String aStr;
        while (nCol >= 26)
        {
            SCCOL nC = nCol % 26;
            aStr += static_cast<sal_Unicode>( 'A' +
                    static_cast<sal_uInt16>(nC));
            nCol = sal::static_int_cast<SCCOL>( nCol - nC );
            nCol = nCol / 26 - 1;
        }
        aStr += static_cast<sal_Unicode>( 'A' +
                static_cast<sal_uInt16>(nCol));
        aStr.Reverse();
        rBuf.append( aStr);
    }
}
---snip---

How does this work?

The true part of the "if (nCol < 26*26)" is an optimization for smaller values,
the "else" is the general algorithm for larger values:

---snip---
String aStr;
while (nCol >= 26)
{
    SCCOL nC = nCol % 26;
    aStr += static_cast<sal_Unicode>( 'A' +
            static_cast<sal_uInt16>(nC));
    nCol = sal::static_int_cast<SCCOL>( nCol - nC );
    nCol = nCol / 26 - 1;
}
aStr += static_cast<sal_Unicode>( 'A' +
        static_cast<sal_uInt16>(nCol));
aStr.Reverse();
---snip---

That subtraction of 1 is confusing...

Let's consider what happens for different values of nCol:

0 <= nCol < 26:
- the while loop is skipped.
- the result has 1 digit, 'A' + nCol,
  A=0, B=1, C=2, ..., Z=25.

26 <= nCol < 702 (27*26)
- the while loop runs once
- the result has 2 digits:
  - first digit is 'A' + floor((nCol / 26) - 1)
  - last digit is 'A' + (nCol % 26)

701 (27*26) <= nCol < 18278 (702*26)
- the while loop runs twice
- the result has 3 digits:
  - first digit is 'A' + (floor((floor(nCol / 26) - 1) / 26) - 1)
  - middle digit is 'A' + ((floor(nCol / 26) - 1) % 26)
  - last digit is 'A' + (nCol % 26)


So:

If (701 < nCol < 18728), the first digit will be
'A' + (floor((floor(nCol / 26) - 1) / 26) - 1).

If (26 <= nCol), the next digit will be
'A' + ((floor(nCol / 26) - 1) % 26)

The last digit will always be
'A' + (nCol % 26)

Now how to translate this into the declarative format of XSLT?

-- 
You are receiving this mail because:
You are the assignee for the issue.

Reply via email to