summaryrefslogtreecommitdiffstats
path: root/basic
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2022-01-30 14:12:46 +0300
committerXisco Fauli <xiscofauli@libreoffice.org>2022-02-07 17:06:31 +0100
commit3fa7c7618500bf5914e19cb3714f301f7bff305a (patch)
tree3f25ea27ebd31c9cae6a469f37e3ecb97506b6c8 /basic
parentqt5: crash entering ë with french IM (diff)
downloadcore-3fa7c7618500bf5914e19cb3714f301f7bff305a.tar.gz
core-3fa7c7618500bf5914e19cb3714f301f7bff305a.zip
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.kaganski@collabora.com> Signed-off-by: Xisco Fauli <xiscofauli@libreoffice.org> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129208 (cherry picked from commit 8efa3dd53aaf98ed258c9f340800504c9e874b78) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129257
Diffstat (limited to 'basic')
-rw-r--r--basic/source/runtime/methods.cxx63
1 files changed, 38 insertions, 25 deletions
diff --git a/basic/source/runtime/methods.cxx b/basic/source/runtime/methods.cxx
index e3a30f324525..d4a4ce74ed0a 100644
--- a/basic/source/runtime/methods.cxx
+++ b/basic/source/runtime/methods.cxx
@@ -68,7 +68,7 @@
#include <o3tl/char16_t2wchar_t.hxx>
// include search util
-#include <com/sun/star/util/SearchFlags.hpp>
+#include <com/sun/star/i18n/Transliteration.hpp>
#include <com/sun/star/util/SearchAlgorithms2.hpp>
#include <i18nutil/searchopt.hxx>
#include <unotools/textsearch.hxx>
@@ -1269,6 +1269,7 @@ void SbRtl_Replace(StarBASIC *, SbxArray & rPar, bool)
return;
}
}
+ --lStartPos; // Make it 0-based
sal_Int32 lCount = -1;
if (nArgCount >= 5)
@@ -1304,40 +1305,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());
}