Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2008 by Sun Microsystems, Inc.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include "stringutil.hxx"
30 : : #include "rtl/ustrbuf.hxx"
31 : : #include "rtl/math.hxx"
32 : :
33 : : using ::rtl::OUString;
34 : : using ::rtl::OUStringBuffer;
35 : :
36 : 10354 : ScSetStringParam::ScSetStringParam() :
37 : : mpNumFormatter(NULL),
38 : : mbDetectNumberFormat(true),
39 : : meSetTextNumFormat(Never),
40 : 10354 : mbHandleApostrophe(true)
41 : : {
42 : 10354 : }
43 : :
44 : : // ============================================================================-
45 : :
46 : 1145 : bool ScStringUtil::parseSimpleNumber(
47 : : const OUString& rStr, sal_Unicode dsep, sal_Unicode gsep, double& rVal)
48 : : {
49 : : // Actually almost the entire pre-check is unnecessary and we could call
50 : : // rtl::math::stringToDouble() just after having exchanged ascii space with
51 : : // non-breaking space, if it wasn't for check of grouped digits. The NaN
52 : : // and Inf cases that are accepted by stringToDouble() could be detected
53 : : // using rtl::math::isFinite() on the result.
54 : :
55 : : /* TODO: The grouped digits check isn't even valid for locales that do not
56 : : * group in thousands ... e.g. Indian locales. But that's something also
57 : : * the number scanner doesn't implement yet, only the formatter. */
58 : :
59 : 1145 : OUStringBuffer aBuf;
60 : :
61 : 1145 : sal_Int32 i = 0;
62 : 1145 : sal_Int32 n = rStr.getLength();
63 : 1145 : const sal_Unicode* p = rStr.getStr();
64 : 1145 : const sal_Unicode* pLast = p + (n-1);
65 : 1145 : sal_Int32 nPosDSep = -1, nPosGSep = -1;
66 : 1145 : sal_uInt32 nDigitCount = 0;
67 : 1145 : sal_Int32 nPosExponent = -1;
68 : :
69 : : // Skip preceding spaces.
70 [ + - ]: 1165 : for (i = 0; i < n; ++i, ++p)
71 : : {
72 : 1165 : sal_Unicode c = *p;
73 [ + + ][ + - ]: 1165 : if (c != 0x0020 && c != 0x00A0)
74 : : // first non-space character. Exit.
75 : 1145 : break;
76 : : }
77 : :
78 [ - + ]: 1145 : if (i == n)
79 : : // the whole string is space. Fail.
80 : 0 : return false;
81 : :
82 : 1145 : n -= i; // Subtract the length of the preceding spaces.
83 : :
84 : : // Determine the last non-space character.
85 [ + + ]: 1175 : for (; p != pLast; --pLast, --n)
86 : : {
87 : 845 : sal_Unicode c = *pLast;
88 [ + + ][ + - ]: 845 : if (c != 0x0020 && c != 0x00A0)
89 : : // Non space character. Exit.
90 : 815 : break;
91 : : }
92 : :
93 [ + + ]: 2660 : for (i = 0; i < n; ++i, ++p)
94 : : {
95 : 2080 : sal_Unicode c = *p;
96 [ - + ][ # # ]: 2080 : if (c == 0x0020 && gsep == 0x00A0)
97 : : // ascii space to unicode space if that is group separator
98 : 0 : c = 0x00A0;
99 : :
100 [ + + ][ + + ]: 2080 : if (sal_Unicode('0') <= c && c <= sal_Unicode('9'))
101 : : {
102 : : // this is a digit.
103 [ + - ]: 1345 : aBuf.append(c);
104 : 1345 : ++nDigitCount;
105 : : }
106 [ + + ]: 735 : else if (c == dsep)
107 : : {
108 : : // this is a decimal separator.
109 : :
110 [ - + ]: 130 : if (nPosDSep >= 0)
111 : : // a second decimal separator -> not a valid number.
112 : 0 : return false;
113 : :
114 [ - + ][ # # ]: 130 : if (nPosGSep >= 0 && i - nPosGSep != 4)
115 : : // the number has a group separator and the decimal sep is not
116 : : // positioned correctly.
117 : 0 : return false;
118 : :
119 : 130 : nPosDSep = i;
120 : 130 : nPosGSep = -1;
121 [ + - ]: 130 : aBuf.append(c);
122 : 130 : nDigitCount = 0;
123 : : }
124 [ + + ]: 605 : else if (c == gsep)
125 : : {
126 : : // this is a group (thousand) separator.
127 : :
128 [ - + ]: 40 : if (i == 0)
129 : : // not allowed as the first character.
130 : 0 : return false;
131 : :
132 [ - + ]: 40 : if (nPosDSep >= 0)
133 : : // not allowed after the decimal separator.
134 : 0 : return false;
135 : :
136 [ + + ][ - + ]: 40 : if (nPosGSep >= 0 && nDigitCount != 3)
137 : : // must be exactly 3 digits since the last group separator.
138 : 0 : return false;
139 : :
140 [ - + ]: 40 : if (nPosExponent >= 0)
141 : : // not allowed in exponent.
142 : 0 : return false;
143 : :
144 : 40 : nPosGSep = i;
145 : 40 : nDigitCount = 0;
146 : : }
147 [ + + ][ - + ]: 565 : else if (c == sal_Unicode('-') || c == sal_Unicode('+'))
148 : : {
149 : : // A sign must be the first character if it's given, or immediately
150 : : // follow the exponent character if present.
151 [ + - ][ - + ]: 40 : if (i == 0 || (nPosExponent >= 0 && i == nPosExponent + 1))
[ # # ]
152 [ # # ]: 0 : aBuf.append(c);
153 : : else
154 : 40 : return false;
155 : : }
156 [ + - ][ - + ]: 525 : else if (c == sal_Unicode('E') || c == sal_Unicode('e'))
157 : : {
158 : : // this is an exponent designator.
159 : :
160 [ # # ]: 0 : if (nPosExponent >= 0)
161 : : // Only one exponent allowed.
162 : 0 : return false;
163 : :
164 [ # # ][ # # ]: 0 : if (nPosGSep >= 0 && nDigitCount != 3)
165 : : // must be exactly 3 digits since the last group separator.
166 : 0 : return false;
167 : :
168 [ # # ]: 0 : aBuf.append(c);
169 : 0 : nPosExponent = i;
170 : 0 : nPosDSep = -1;
171 : 0 : nPosGSep = -1;
172 : 0 : nDigitCount = 0;
173 : : }
174 : : else
175 : 525 : return false;
176 : : }
177 : :
178 : : // finished parsing the number.
179 : :
180 [ + + ][ + + ]: 580 : if (nPosGSep >= 0 && nDigitCount != 3)
181 : : // must be exactly 3 digits since the last group separator.
182 : 20 : return false;
183 : :
184 : 560 : rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok;
185 : 560 : sal_Int32 nParseEnd = 0;
186 [ + - ]: 560 : OUString aString( aBuf.makeStringAndClear());
187 : 560 : rVal = ::rtl::math::stringToDouble( aString, dsep, gsep, &eStatus, &nParseEnd);
188 [ - + ][ - + ]: 560 : if (eStatus != rtl_math_ConversionStatus_Ok || nParseEnd < aString.getLength())
[ + - ]
189 : : // Not a valid number or not entire string consumed.
190 : 0 : return false;
191 : :
192 : 1145 : return true;
193 : : }
194 : :
195 : 0 : xub_StrLen ScStringUtil::GetQuotedTokenCount(const UniString &rIn, const UniString& rQuotedPairs, sal_Unicode cTok )
196 : : {
197 : : assert( !(rQuotedPairs.Len()%2) );
198 : : assert( rQuotedPairs.Search(cTok) );
199 : :
200 : : // Leerer String: TokenCount per Definition 0
201 [ # # ]: 0 : if ( !rIn.Len() )
202 : 0 : return 0;
203 : :
204 : 0 : xub_StrLen nTokCount = 1;
205 : 0 : sal_Int32 nLen = rIn.Len();
206 : 0 : xub_StrLen nQuotedLen = rQuotedPairs.Len();
207 : 0 : sal_Unicode cQuotedEndChar = 0;
208 : 0 : const sal_Unicode* pQuotedStr = rQuotedPairs.GetBuffer();
209 : 0 : const sal_Unicode* pStr = rIn.GetBuffer();
210 : 0 : sal_Int32 nIndex = 0;
211 [ # # ]: 0 : while ( nIndex < nLen )
212 : : {
213 : 0 : sal_Unicode c = *pStr;
214 [ # # ]: 0 : if ( cQuotedEndChar )
215 : : {
216 : : // Ende des Quotes erreicht ?
217 [ # # ]: 0 : if ( c == cQuotedEndChar )
218 : 0 : cQuotedEndChar = 0;
219 : : }
220 : : else
221 : : {
222 : : // Ist das Zeichen ein Quote-Anfang-Zeichen ?
223 : 0 : xub_StrLen nQuoteIndex = 0;
224 [ # # ]: 0 : while ( nQuoteIndex < nQuotedLen )
225 : : {
226 [ # # ]: 0 : if ( pQuotedStr[nQuoteIndex] == c )
227 : : {
228 : 0 : cQuotedEndChar = pQuotedStr[nQuoteIndex+1];
229 : 0 : break;
230 : : }
231 : : else
232 : 0 : nQuoteIndex += 2;
233 : : }
234 : :
235 : : // Stimmt das Tokenzeichen ueberein, dann erhoehe TokCount
236 [ # # ]: 0 : if ( c == cTok )
237 : 0 : ++nTokCount;
238 : : }
239 : :
240 : : ++pStr,
241 : 0 : ++nIndex;
242 : : }
243 : :
244 : 0 : return nTokCount;
245 : : }
246 : :
247 : 0 : UniString ScStringUtil::GetQuotedToken(const UniString &rIn, xub_StrLen nToken, const UniString& rQuotedPairs,
248 : : sal_Unicode cTok, xub_StrLen& rIndex )
249 : : {
250 : : assert( !(rQuotedPairs.Len()%2) );
251 : : assert( rQuotedPairs.Search(cTok) == STRING_NOTFOUND );
252 : :
253 : 0 : const sal_Unicode* pStr = rIn.GetBuffer();
254 : 0 : const sal_Unicode* pQuotedStr = rQuotedPairs.GetBuffer();
255 : 0 : sal_Unicode cQuotedEndChar = 0;
256 : 0 : xub_StrLen nQuotedLen = rQuotedPairs.Len();
257 : 0 : xub_StrLen nLen = rIn.Len();
258 : 0 : xub_StrLen nTok = 0;
259 : 0 : xub_StrLen nFirstChar = rIndex;
260 : 0 : xub_StrLen i = nFirstChar;
261 : :
262 : : // Bestimme die Token-Position und Laenge
263 : 0 : pStr += i;
264 [ # # ]: 0 : while ( i < nLen )
265 : : {
266 : 0 : sal_Unicode c = *pStr;
267 [ # # ]: 0 : if ( cQuotedEndChar )
268 : : {
269 : : // Ende des Quotes erreicht ?
270 [ # # ]: 0 : if ( c == cQuotedEndChar )
271 : 0 : cQuotedEndChar = 0;
272 : : }
273 : : else
274 : : {
275 : : // Ist das Zeichen ein Quote-Anfang-Zeichen ?
276 : 0 : xub_StrLen nQuoteIndex = 0;
277 [ # # ]: 0 : while ( nQuoteIndex < nQuotedLen )
278 : : {
279 [ # # ]: 0 : if ( pQuotedStr[nQuoteIndex] == c )
280 : : {
281 : 0 : cQuotedEndChar = pQuotedStr[nQuoteIndex+1];
282 : 0 : break;
283 : : }
284 : : else
285 : 0 : nQuoteIndex += 2;
286 : : }
287 : :
288 : : // Stimmt das Tokenzeichen ueberein, dann erhoehe TokCount
289 [ # # ]: 0 : if ( c == cTok )
290 : : {
291 : 0 : ++nTok;
292 : :
293 [ # # ]: 0 : if ( nTok == nToken )
294 : 0 : nFirstChar = i+1;
295 : : else
296 : : {
297 [ # # ]: 0 : if ( nTok > nToken )
298 : 0 : break;
299 : : }
300 : : }
301 : : }
302 : :
303 : : ++pStr,
304 : 0 : ++i;
305 : : }
306 : :
307 [ # # ]: 0 : if ( nTok >= nToken )
308 : : {
309 [ # # ]: 0 : if ( i < nLen )
310 : 0 : rIndex = i+1;
311 : : else
312 : 0 : rIndex = STRING_NOTFOUND;
313 : 0 : return rIn.Copy( nFirstChar, i-nFirstChar );
314 : : }
315 : : else
316 : : {
317 : 0 : rIndex = STRING_NOTFOUND;
318 : 0 : return UniString();
319 : : }
320 : : }
321 : :
322 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|