diff options
author | Andreas Heinisch <andreas.heinisch@yahoo.de> | 2021-07-11 21:06:23 +0200 |
---|---|---|
committer | Andreas Heinisch <andreas.heinisch@yahoo.de> | 2021-07-12 20:30:19 +0200 |
commit | 7e5c9220ef5d51ac23e618c5c9eeda9cf4339c88 (patch) | |
tree | e6ed4ef122e536e25d60f77c947842c2334308dd | |
parent | cffd97193f7468f770368559d5a5c58bd0bb2327 (diff) |
tdf#142487 - use utl::TextSearch in order to implement the replace algorithm
In the old algorithm, some special unicode characters lead to a
malfunction of basic's replace function. For instance, replacing a
German ß to uppercase in the insensitive case will lead to SS, breaking
the replace positions.
Change-Id: I4e6f6e5fba3d560b8cfd0786fa2439ed5174a928
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/118760
Tested-by: Jenkins
Reviewed-by: Andreas Heinisch <andreas.heinisch@yahoo.de>
-rw-r--r-- | basic/CppunitTest_basic_macros.mk | 1 | ||||
-rw-r--r-- | basic/qa/basic_coverage/test_string_replace.bas | 9 | ||||
-rw-r--r-- | basic/source/runtime/methods.cxx | 44 |
3 files changed, 34 insertions, 20 deletions
diff --git a/basic/CppunitTest_basic_macros.mk b/basic/CppunitTest_basic_macros.mk index c2c1eb5b7a04..c70bfff42c68 100644 --- a/basic/CppunitTest_basic_macros.mk +++ b/basic/CppunitTest_basic_macros.mk @@ -61,6 +61,7 @@ $(eval $(call gb_CppunitTest_use_vcl,basic_macros)) $(eval $(call gb_CppunitTest_use_components,basic_macros,\ configmgr/source/configmgr \ + i18npool/source/search/i18nsearch \ i18npool/util/i18npool \ ucb/source/core/ucb1 \ ucb/source/ucp/file/ucpfile1 \ diff --git a/basic/qa/basic_coverage/test_string_replace.bas b/basic/qa/basic_coverage/test_string_replace.bas index 4dfac668109d..d68f36fbb662 100644 --- a/basic/qa/basic_coverage/test_string_replace.bas +++ b/basic/qa/basic_coverage/test_string_replace.bas @@ -24,7 +24,14 @@ Sub verify_stringReplace() ' tdf#143081 - Without the fix in place, this test would have crashed here retStr = Replace("""Straße""", """", """) - TestUtil.AssertEqual(retStr, ""Straße"""", "replace doesn't crash: " & retStr) + TestUtil.AssertEqual(retStr, ""Straße"", "replace doesn't crash: " & retStr) + + ' tdf#142487 - replace of special unicode characters. + ' Without the fix in place, this test would have failed with: + ' - Expected: Straßen + ' - Actual : Straßeen + retStr = Replace("Straße", "e", "en") + TestUtil.AssertEqual(retStr, "Straßen", "special unicode character: " & retStr) Exit Sub errorHandler: diff --git a/basic/source/runtime/methods.cxx b/basic/source/runtime/methods.cxx index 41f0d38ec1b0..e745fa2fd1c6 100644 --- a/basic/source/runtime/methods.cxx +++ b/basic/source/runtime/methods.cxx @@ -67,6 +67,14 @@ #include <string_view> #include <o3tl/char16_t2wchar_t.hxx> +// include search util +#include <com/sun/star/util/SearchFlags.hpp> +#include <com/sun/star/util/SearchAlgorithms2.hpp> +#include <i18nutil/searchopt.hxx> +#include <unotools/textsearch.hxx> + + + using namespace comphelper; using namespace osl; using namespace com::sun::star; @@ -1283,34 +1291,32 @@ void SbRtl_Replace(StarBASIC *, SbxArray & rPar, bool) } const OUString aExpStr = rPar.Get(1)->GetOUString(); - OUString aFindStr = rPar.Get(2)->GetOUString(); + const 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(); - OUString aSrcStr(aExpStr); + // tdf#142487 - use utl::TextSearch in order to implement the replace algorithm + i18nutil::SearchOptions2 aSearchOptions; + aSearchOptions.searchString = aFindStr; + aSearchOptions.AlgorithmType2 = util::SearchAlgorithms2::ABSOLUTE; if (bCaseInsensitive) - { - // tdf#132389 - case-insensitive operation for non-ASCII characters - const css::lang::Locale& rLocale = Application::GetSettings().GetLanguageTag().getLocale(); - css::uno::Reference<i18n::XCharacterClassification> xCharClass - = vcl::unohelper::CreateCharacterClassification(); - aSrcStr = xCharClass->toUpper(aSrcStr, 0, aSrcStr.getLength(), rLocale); - aFindStr = xCharClass->toUpper(aFindStr, 0, aFindStr.getLength(), rLocale); - } - const sal_Int32 nSrcStrLen = aSrcStr.getLength(); - const sal_Int32 nFindStrLen = aFindStr.getLength(); + aSearchOptions.transliterateFlags |= TransliterationFlags::IGNORE_CASE; + utl::TextSearch textSearch(aSearchOptions); // Note: the result starts from lStartPos, removing everything to the left. See i#94895. - sal_Int32 nPrevPos = std::min(lStartPos - 1, nSrcStrLen); - OUStringBuffer sResult(nSrcStrLen - nPrevPos); + sal_Int32 nPrevPos = std::min(lStartPos - 1, nExpStrLen); + OUStringBuffer sResult(nExpStrLen - nPrevPos); sal_Int32 nCounts = 0; while (lCount == -1 || lCount > nCounts) { - sal_Int32 nPos = aSrcStr.indexOf(aFindStr, nPrevPos); - if (nPos >= 0) + sal_Int32 nStartPos = nPrevPos; + sal_Int32 aEndPos = aExpStr.getLength(); + if (textSearch.SearchForward(aExpStr, &nStartPos, &aEndPos)) { - sResult.append(aExpStr.getStr() + nPrevPos, nPos - nPrevPos); + sResult.append(aExpStr.getStr() + nPrevPos, nStartPos - nPrevPos); sResult.append(aReplaceStr); - nPrevPos = nPos + nFindStrLen; + nPrevPos = nStartPos + nFindStrLen; nCounts++; } else @@ -1318,7 +1324,7 @@ void SbRtl_Replace(StarBASIC *, SbxArray & rPar, bool) break; } } - sResult.append(aExpStr.getStr() + nPrevPos, nSrcStrLen - nPrevPos); + sResult.append(aExpStr.getStr() + nPrevPos, nExpStrLen - nPrevPos); rPar.Get(0)->PutString(sResult.makeStringAndClear()); } |