basic/source/runtime/methods.cxx |   62 +++++++++++++++++++++++----------------
 1 file changed, 38 insertions(+), 24 deletions(-)

New commits:
commit a03b7d2a8d0f0fd7e710202bbeecf165f0fcd06a
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Sun Jan 30 14:12:46 2022 +0300
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Sun Jan 30 15:19:39 2022 +0100

    tdf#132388: reimplement fix for tdf#142487
    
    Each call to css::i18n::XTextSearch::SearchForward transliterates input 
string,
    making performance of repeated calls unacceptable. So prepare the 
transliterated
    strings once, and use the offset sequence to map search results to indices 
into
    original string.
    
    Change-Id: Ie08dd5a408aca9a950067db285a480b41a3f9a16
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129162
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/basic/source/runtime/methods.cxx b/basic/source/runtime/methods.cxx
index 2361466ea5e3..26350d6d85f3 100644
--- a/basic/source/runtime/methods.cxx
+++ b/basic/source/runtime/methods.cxx
@@ -67,6 +67,7 @@
 #include <o3tl/char16_t2wchar_t.hxx>
 
 // include search util
+#include <com/sun/star/i18n/Transliteration.hpp>
 #include <com/sun/star/util/SearchAlgorithms2.hpp>
 #include <i18nutil/searchopt.hxx>
 #include <unotools/textsearch.hxx>
@@ -1263,6 +1264,7 @@ void SbRtl_Replace(StarBASIC *, SbxArray & rPar, bool)
             return;
         }
     }
+    --lStartPos; // Make it 0-based
 
     sal_Int32 lCount = -1;
     if (nArgCount >= 5)
@@ -1298,40 +1300,52 @@ void SbRtl_Replace(StarBASIC *, SbxArray & rPar, bool)
     }
 
     const OUString aExpStr = rPar.Get(1)->GetOUString();
-    const OUString aFindStr = rPar.Get(2)->GetOUString();
+    OUString aFindStr = rPar.Get(2)->GetOUString();
     const OUString aReplaceStr = rPar.Get(3)->GetOUString();
-    const sal_Int32 nExpStrLen = aExpStr.getLength();
-    const sal_Int32 nFindStrLen = aFindStr.getLength();
 
-    // tdf#142487 - use utl::TextSearch in order to implement the replace 
algorithm
-    i18nutil::SearchOptions2 aSearchOptions;
-    aSearchOptions.searchString = aFindStr;
-    aSearchOptions.AlgorithmType2 = util::SearchAlgorithms2::ABSOLUTE;
+    OUString aSrcStr(aExpStr);
+    sal_Int32 nPrevPos = std::min(lStartPos, aSrcStr.getLength());
+    css::uno::Sequence<sal_Int32> aOffset;
     if (bCaseInsensitive)
-        aSearchOptions.transliterateFlags |= TransliterationFlags::IGNORE_CASE;
-    utl::TextSearch textSearch(aSearchOptions);
+    {
+        // tdf#132389: case-insensitive operation for non-ASCII characters
+        // tdf#142487: use css::i18n::Transliteration to correctly handle ß -> 
ss expansion
+        // tdf#132388: We can't use utl::TextSearch (css::i18n::XTextSearch), 
because each call to
+        //             css::i18n::XTextSearch::SearchForward transliterates 
input string, making
+        //             performance of repeated calls unacceptable
+        auto xTrans = 
css::i18n::Transliteration::create(comphelper::getProcessComponentContext());
+        xTrans->loadModule(css::i18n::TransliterationModules_IGNORE_CASE, {});
+        aFindStr = xTrans->transliterate(aFindStr, 0, aFindStr.getLength(), 
aOffset);
+        aSrcStr = xTrans->transliterate(aSrcStr, nPrevPos, aSrcStr.getLength() 
- nPrevPos, aOffset);
+        nPrevPos = std::distance(aOffset.begin(),
+                                 std::lower_bound(aOffset.begin(), 
aOffset.end(), nPrevPos));
+    }
+
+    auto getExpStrPos = [aOffset, nExpLen = aExpStr.getLength()](sal_Int32 
nSrcStrPos) -> sal_Int32
+    {
+        assert(!aOffset.hasElements() || aOffset.getLength() >= nSrcStrPos);
+        if (!aOffset.hasElements())
+            return nSrcStrPos;
+        return aOffset.getLength() > nSrcStrPos ? aOffset[nSrcStrPos] : 
nExpLen;
+    };
 
     // Note: the result starts from lStartPos, removing everything to the 
left. See i#94895.
-    sal_Int32 nPrevPos = std::min(lStartPos - 1, nExpStrLen);
-    OUStringBuffer sResult(nExpStrLen - nPrevPos);
+    OUStringBuffer sResult(aSrcStr.getLength() - nPrevPos);
     sal_Int32 nCounts = 0;
     while (lCount == -1 || lCount > nCounts)
     {
-        sal_Int32 nStartPos = nPrevPos;
-        sal_Int32 aEndPos = aExpStr.getLength();
-        if (textSearch.SearchForward(aExpStr, &nStartPos, &aEndPos))
-        {
-            sResult.append(aExpStr.getStr() + nPrevPos, nStartPos - nPrevPos);
-            sResult.append(aReplaceStr);
-            nPrevPos = nStartPos + nFindStrLen;
-            nCounts++;
-        }
-        else
-        {
+        sal_Int32 nPos = aSrcStr.indexOf(aFindStr, nPrevPos);
+        if (nPos < 0)
             break;
-        }
+
+        lStartPos = getExpStrPos(nPrevPos);
+        sResult.append(aExpStr.getStr() + lStartPos, getExpStrPos(nPos) - 
lStartPos);
+        sResult.append(aReplaceStr);
+        nPrevPos = nPos + aFindStr.getLength();
+        nCounts++;
     }
-    sResult.append(aExpStr.getStr() + nPrevPos, nExpStrLen - nPrevPos);
+    lStartPos = getExpStrPos(nPrevPos);
+    sResult.append(aExpStr.getStr() + lStartPos, aExpStr.getLength() - 
lStartPos);
     rPar.Get(0)->PutString(sResult.makeStringAndClear());
 }
 

Reply via email to