Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <i18nlangtag/languagetag.hxx>
21 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
22 : #include <com/sun/star/util/TextSearch.hpp>
23 : #include <com/sun/star/util/SearchFlags.hpp>
24 : #include <com/sun/star/i18n/TransliterationModules.hpp>
25 : #include <unotools/charclass.hxx>
26 : #include <comphelper/processfactory.hxx>
27 : #include <unotools/textsearch.hxx>
28 : #include <rtl/instance.hxx>
29 : #include <rtl/ustrbuf.hxx>
30 :
31 : using namespace ::com::sun::star::util;
32 : using namespace ::com::sun::star::uno;
33 : using namespace ::com::sun::star::lang;
34 :
35 : // ............................................................................
36 : namespace utl
37 : {
38 : // ............................................................................
39 :
40 6 : SearchParam::SearchParam( const OUString &rText,
41 : SearchType eType,
42 : bool bCaseSensitive,
43 : bool bWrdOnly,
44 6 : bool bSearchInSel )
45 : {
46 6 : sSrchStr = rText;
47 6 : m_eSrchType = eType;
48 :
49 6 : m_bWordOnly = bWrdOnly;
50 6 : m_bSrchInSel = bSearchInSel;
51 6 : m_bCaseSense = bCaseSensitive;
52 :
53 6 : nTransliterationFlags = 0;
54 :
55 : // Parameters for weighted Levenshtein distance
56 6 : bLEV_Relaxed = true;
57 6 : nLEV_OtherX = 2;
58 6 : nLEV_ShorterY = 1;
59 6 : nLEV_LongerZ = 3;
60 6 : }
61 :
62 0 : SearchParam::SearchParam( const SearchParam& rParam )
63 : {
64 0 : sSrchStr = rParam.sSrchStr;
65 0 : sReplaceStr = rParam.sReplaceStr;
66 0 : m_eSrchType = rParam.m_eSrchType;
67 :
68 0 : m_bWordOnly = rParam.m_bWordOnly;
69 0 : m_bSrchInSel = rParam.m_bSrchInSel;
70 0 : m_bCaseSense = rParam.m_bCaseSense;
71 :
72 0 : bLEV_Relaxed = rParam.bLEV_Relaxed;
73 0 : nLEV_OtherX = rParam.nLEV_OtherX;
74 0 : nLEV_ShorterY = rParam.nLEV_ShorterY;
75 0 : nLEV_LongerZ = rParam.nLEV_LongerZ;
76 :
77 0 : nTransliterationFlags = rParam.nTransliterationFlags;
78 0 : }
79 :
80 6 : SearchParam::~SearchParam() {}
81 :
82 87 : static bool lcl_Equals( const SearchOptions& rSO1, const SearchOptions& rSO2 )
83 : {
84 172 : return rSO1.algorithmType == rSO2.algorithmType &&
85 164 : rSO1.searchFlag == rSO2.searchFlag &&
86 119 : rSO1.searchString.equals(rSO2.searchString) &&
87 77 : rSO1.replaceString.equals(rSO2.replaceString) &&
88 74 : rSO1.changedChars == rSO2.changedChars &&
89 74 : rSO1.deletedChars == rSO2.deletedChars &&
90 74 : rSO1.insertedChars == rSO2.insertedChars &&
91 74 : rSO1.Locale.Language == rSO2.Locale.Language &&
92 74 : rSO1.Locale.Country == rSO2.Locale.Country &&
93 161 : rSO1.Locale.Variant == rSO2.Locale.Variant &&
94 124 : rSO1.transliterateFlags == rSO2.transliterateFlags;
95 : }
96 :
97 : namespace
98 : {
99 14 : struct CachedTextSearch
100 : {
101 : ::osl::Mutex mutex;
102 : ::com::sun::star::util::SearchOptions Options;
103 : ::com::sun::star::uno::Reference< ::com::sun::star::util::XTextSearch > xTextSearch;
104 : };
105 :
106 : struct theCachedTextSearch
107 : : public rtl::Static< CachedTextSearch, theCachedTextSearch > {};
108 : }
109 :
110 87 : Reference<XTextSearch> TextSearch::getXTextSearch( const SearchOptions& rPara )
111 : {
112 87 : CachedTextSearch &rCache = theCachedTextSearch::get();
113 :
114 87 : osl::MutexGuard aGuard(rCache.mutex);
115 :
116 87 : if ( lcl_Equals(rCache.Options, rPara) )
117 37 : return rCache.xTextSearch;
118 :
119 100 : Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
120 50 : rCache.xTextSearch.set( ::TextSearch::create(xContext) );
121 50 : rCache.xTextSearch->setOptions( rPara );
122 50 : rCache.Options = rPara;
123 :
124 137 : return rCache.xTextSearch;
125 : }
126 :
127 0 : TextSearch::TextSearch(const SearchParam & rParam, LanguageType eLang )
128 : {
129 0 : if( LANGUAGE_NONE == eLang )
130 0 : eLang = LANGUAGE_SYSTEM;
131 0 : ::com::sun::star::lang::Locale aLocale( LanguageTag( eLang ).getLocale() );
132 :
133 0 : Init( rParam, aLocale);
134 0 : }
135 :
136 6 : TextSearch::TextSearch(const SearchParam & rParam, const CharClass& rCClass )
137 : {
138 6 : Init( rParam, rCClass.getLanguageTag().getLocale() );
139 6 : }
140 :
141 81 : TextSearch::TextSearch( const SearchOptions& rPara )
142 : {
143 81 : xTextSearch = getXTextSearch( rPara );
144 81 : }
145 :
146 6 : void TextSearch::Init( const SearchParam & rParam,
147 : const ::com::sun::star::lang::Locale& rLocale )
148 : {
149 : // convert SearchParam to the UNO SearchOptions
150 6 : SearchOptions aSOpt;
151 :
152 6 : switch( rParam.GetSrchType() )
153 : {
154 : case SearchParam::SRCH_REGEXP:
155 6 : aSOpt.algorithmType = SearchAlgorithms_REGEXP;
156 6 : if( rParam.IsSrchInSelection() )
157 : aSOpt.searchFlag |= SearchFlags::REG_NOT_BEGINOFLINE |
158 0 : SearchFlags::REG_NOT_ENDOFLINE;
159 6 : break;
160 :
161 : case SearchParam::SRCH_LEVDIST:
162 0 : aSOpt.algorithmType = SearchAlgorithms_APPROXIMATE;
163 0 : aSOpt.changedChars = rParam.GetLEVOther();
164 0 : aSOpt.deletedChars = rParam.GetLEVLonger();
165 0 : aSOpt.insertedChars = rParam.GetLEVShorter();
166 0 : if( rParam.IsSrchRelaxed() )
167 0 : aSOpt.searchFlag |= SearchFlags::LEV_RELAXED;
168 0 : break;
169 :
170 : // case SearchParam::SRCH_NORMAL:
171 : default:
172 0 : aSOpt.algorithmType = SearchAlgorithms_ABSOLUTE;
173 0 : if( rParam.IsSrchWordOnly() )
174 0 : aSOpt.searchFlag |= SearchFlags::NORM_WORD_ONLY;
175 0 : break;
176 : }
177 6 : aSOpt.searchString = rParam.GetSrchStr();
178 6 : aSOpt.replaceString = rParam.GetReplaceStr();
179 6 : aSOpt.Locale = rLocale;
180 6 : aSOpt.transliterateFlags = rParam.GetTransliterationFlags();
181 6 : if( !rParam.IsCaseSensitive() )
182 : {
183 6 : aSOpt.searchFlag |= SearchFlags::ALL_IGNORE_CASE;
184 6 : aSOpt.transliterateFlags |= ::com::sun::star::i18n::TransliterationModules_IGNORE_CASE;
185 : }
186 :
187 6 : xTextSearch = getXTextSearch( aSOpt );
188 6 : }
189 :
190 0 : void TextSearch::SetLocale( const ::com::sun::star::util::SearchOptions& rOptions,
191 : const ::com::sun::star::lang::Locale& rLocale )
192 : {
193 : // convert SearchParam to the UNO SearchOptions
194 0 : SearchOptions aSOpt( rOptions );
195 0 : aSOpt.Locale = rLocale;
196 :
197 0 : xTextSearch = getXTextSearch( aSOpt );
198 0 : }
199 :
200 :
201 87 : TextSearch::~TextSearch()
202 : {
203 87 : }
204 :
205 : /*
206 : * General search methods. These methods will call the respective
207 : * methods, such as ordinary string searching or regular expression
208 : * matching, using the method pointer.
209 : */
210 1191 : bool TextSearch::SearchForward( const OUString &rStr,
211 : sal_Int32* pStart, sal_Int32* pEnd,
212 : ::com::sun::star::util::SearchResult* pRes)
213 : {
214 1191 : bool nRet = false;
215 : try
216 : {
217 1191 : if( xTextSearch.is() )
218 : {
219 1191 : SearchResult aRet( xTextSearch->searchForward( rStr, *pStart, *pEnd ));
220 1191 : if( aRet.subRegExpressions > 0 )
221 : {
222 778 : nRet = true;
223 : // the XTextsearch returns in startOffset the higher position
224 : // and the endposition is always exclusive.
225 : // The caller of this function will have in startPos the
226 : // lower pos. and end
227 778 : *pStart = aRet.startOffset[ 0 ];
228 778 : *pEnd = aRet.endOffset[ 0 ];
229 778 : if( pRes )
230 686 : *pRes = aRet;
231 1191 : }
232 : }
233 : }
234 0 : catch ( Exception& )
235 : {
236 : SAL_WARN( "unotools.i18n", "SearchForward: Exception caught!" );
237 : }
238 1191 : return nRet;
239 : }
240 :
241 :
242 0 : bool TextSearch::SearchBackward( const OUString & rStr, sal_Int32* pStart,
243 : sal_Int32* pEnde, SearchResult* pRes )
244 : {
245 0 : bool nRet = false;
246 : try
247 : {
248 0 : if( xTextSearch.is() )
249 : {
250 0 : SearchResult aRet( xTextSearch->searchBackward( rStr, *pStart, *pEnde ));
251 0 : if( aRet.subRegExpressions )
252 : {
253 0 : nRet = true;
254 : // the XTextsearch returns in startOffset the higher position
255 : // and the endposition is always exclusive.
256 : // The caller of this function will have in startPos the
257 : // lower pos. and end
258 0 : *pEnde = aRet.startOffset[ 0 ];
259 0 : *pStart = aRet.endOffset[ 0 ];
260 0 : if( pRes )
261 0 : *pRes = aRet;
262 0 : }
263 : }
264 : }
265 0 : catch ( Exception& )
266 : {
267 : SAL_WARN( "unotools.i18n", "SearchBackward: Exception caught!" );
268 : }
269 0 : return nRet;
270 : }
271 :
272 269 : void TextSearch::ReplaceBackReferences( OUString& rReplaceStr, const OUString &rStr, const SearchResult& rResult )
273 : {
274 269 : if( rResult.subRegExpressions > 0 )
275 : {
276 : sal_Unicode sFndChar;
277 : sal_Int32 i;
278 269 : OUStringBuffer sBuff(rReplaceStr.getLength()*4);
279 2233 : for(i = 0; i < rReplaceStr.getLength(); i++)
280 : {
281 1964 : if( rReplaceStr[i] == '&')
282 : {
283 0 : sal_Int32 nStart = rResult.startOffset[0];
284 0 : sal_Int32 nLength = rResult.endOffset[0] - rResult.startOffset[0];
285 0 : sBuff.append(rStr.getStr() + nStart, nLength);
286 : }
287 1964 : else if( rReplaceStr[i] == '$' && i < rReplaceStr.getLength() - 1)
288 : {
289 0 : sFndChar = rReplaceStr[ i + 1 ];
290 0 : switch(sFndChar)
291 : { // placeholder for a backward reference?
292 : case '0':
293 : case '1':
294 : case '2':
295 : case '3':
296 : case '4':
297 : case '5':
298 : case '6':
299 : case '7':
300 : case '8':
301 : case '9':
302 : {
303 0 : int j = sFndChar - '0'; // index
304 0 : if(j < rResult.subRegExpressions)
305 : {
306 0 : sal_Int32 nSttReg = rResult.startOffset[j];
307 0 : sal_Int32 nRegLen = rResult.endOffset[j];
308 0 : if( nRegLen > nSttReg )
309 : {
310 0 : nRegLen = nRegLen - nSttReg;
311 : }
312 : else
313 : {
314 0 : nRegLen = nSttReg - nRegLen;
315 0 : nSttReg = rResult.endOffset[j];
316 : }
317 : // Copy reference from found string
318 0 : sBuff.append(rStr.getStr() + nSttReg, nRegLen);
319 : }
320 0 : i += 1;
321 : }
322 0 : break;
323 : default:
324 0 : sBuff.append(rReplaceStr[i]);
325 0 : sBuff.append(rReplaceStr[i+1]);
326 0 : i += 1;
327 0 : break;
328 : }
329 : }
330 1964 : else if( rReplaceStr[i] == '\\' && i < rReplaceStr.getLength() - 1)
331 : {
332 0 : sFndChar = rReplaceStr[ i+1 ];
333 0 : switch(sFndChar)
334 : {
335 : case '\\':
336 : case '&':
337 : case '$':
338 0 : sBuff.append(sFndChar);
339 0 : i+=1;
340 0 : break;
341 : case 't':
342 0 : sBuff.append('\t');
343 0 : i += 1;
344 0 : break;
345 : default:
346 0 : sBuff.append(rReplaceStr[i]);
347 0 : sBuff.append(rReplaceStr[i+1]);
348 0 : i += 1;
349 0 : break;
350 : }
351 : }
352 : else
353 : {
354 1964 : sBuff.append(rReplaceStr[i]);
355 : }
356 : }
357 269 : rReplaceStr = sBuff.makeStringAndClear();
358 : }
359 269 : }
360 :
361 : // ............................................................................
362 : } // namespace utl
363 : // ............................................................................
364 :
365 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|