related tdf#156105 sw UI: recognize '%' in numbering prefix/suffix

bug 156105's listWithPercents.odt is an example of a
properly defined ListFormat which contains a percent symbol
in the prefix and suffix, which looked fine in the document itself,
but was cut off short in the UI.

sw/qa/extras/ooxmlexport/data/tdf116883.docx is also an example,
which can be seen if you reduce the first entry to level 1
instead of level 2.
Level 1 is improperly defined as "1%>". This is invalid formatting,
so the entire thing should be considered a suffix.
MS Word also considers it to be a suffix.

This code segment still isn't completely comprehensive
because it won't properly parse "%1xyz%1%." and "%1xyz%10%."
but I'm losing patience.

There is still a potential problem with the
nInclUpperLevels calculation in case
a '%' is used as an in-between separator,
but that seems extremely theoretical and irrelevant to me.
IIUC, the main impact is that it shows some extra dots
in the bullets and numbering UI preview.

Change-Id: Ic1b8fbda62917ad4c7b88bf4fff136d72242f977
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167782
Reviewed-by: Justin Luth <jluth@mail.com>
Reviewed-by: Vasily Melenchuk <vasily.melenchuk@cib.de>
Tested-by: Jenkins
diff --git a/editeng/source/items/numitem.cxx b/editeng/source/items/numitem.cxx
index b81172f..0d677df 100644
--- a/editeng/source/items/numitem.cxx
+++ b/editeng/source/items/numitem.cxx
@@ -626,17 +626,39 @@ void SvxNumberFormat::SetListFormat(std::optional<OUString> oSet)
    // For backward compatibility and UI we should create something looking like
    // a prefix, suffix and included levels also. This is not possible in general case
    // since level format string is much more flexible. But for most cases is okay

    // If properly formatted, sListFormat should look something like "%1%…%10%"
    // with an optional prefix or suffix (which could theoretically include a percent symbol)
    const sal_Int32 nLen = sListFormat->getLength();
    sal_Int32 nFirstReplacement = sListFormat->indexOf('%');
    sal_Int32 nLastReplacement = sListFormat->lastIndexOf('%') + 1;
    while (nFirstReplacement > -1 && nFirstReplacement < nLen - 1
           && ((*sListFormat)[nFirstReplacement + 1] < '1'
               || (*sListFormat)[nFirstReplacement + 1] > '9'))
    {
        nFirstReplacement = sListFormat->indexOf('%', nFirstReplacement + 1);
    }

    sal_Int32 nLastReplacement = nFirstReplacement == -1 ? -1 : sListFormat->lastIndexOf('%');
    while (nLastReplacement > 0
           && ((*sListFormat)[nLastReplacement - 1] < '0'
               || (*sListFormat)[nLastReplacement - 1] > '9'))
    {
        nLastReplacement = sListFormat->lastIndexOf('%', nLastReplacement);
    }
    if (nLastReplacement < nFirstReplacement)
        nLastReplacement = nFirstReplacement;
    else
        ++nLastReplacement;

    if (nFirstReplacement > 0)
        // Everything before first '%' will be prefix
        sPrefix = sListFormat->copy(0, nFirstReplacement);
    if (nLastReplacement >= 0 && nLastReplacement < sListFormat->getLength())
    if (nLastReplacement >= 0 && nLastReplacement < nLen)
        // Everything beyond last '%' is a suffix
        sSuffix = sListFormat->copy(nLastReplacement);

    sal_uInt8 nPercents = 0;
    for (sal_Int32 i = 0; i < sListFormat->getLength(); i++)
    for (sal_Int32 i = nFirstReplacement > 0 ? nFirstReplacement : 0; i < nLastReplacement; i++)
    {
        if ((*sListFormat)[i] == '%')
            nPercents++;