00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "valueparser.h"
00022
00023 #include "kspread_cell.h"
00024 #include "kspread_format.h"
00025 #include "kspread_locale.h"
00026 #include "kspread_value.h"
00027
00028 using namespace KSpread;
00029
00030 ValueParser::ValueParser( KLocale* locale ) : parserLocale( locale )
00031 {
00032 }
00033
00034 KLocale* ValueParser::locale()
00035 {
00036 return parserLocale;
00037 }
00038
00039 void ValueParser::parse (const QString& str, Cell *cell)
00040 {
00041 FormatType format = cell->formatType();
00042
00043
00044
00045
00046
00047 if ( str.isEmpty() || format == Text_format || str.at(0)=='\'' )
00048 {
00049 cell->setValue (str);
00050 return;
00051 }
00052
00053 QString strStripped = str.stripWhiteSpace();
00054
00055
00056
00057
00058 if (tryParseNumber (strStripped, cell))
00059 return;
00060
00061
00062 if (tryParseBool (strStripped, cell))
00063 return;
00064
00065
00066
00067 bool ok;
00068 double money = parserLocale->readMoney (strStripped, &ok);
00069 if (ok)
00070 {
00071 cell->format()->setPrecision(2);
00072 Value val (money);
00073 val.setFormat (Value::fmt_Money);
00074 cell->setValue (val);
00075 return;
00076 }
00077
00078 if (tryParseDate (strStripped, cell))
00079 return;
00080
00081 if (tryParseTime (strStripped, cell))
00082 return;
00083
00084
00085 cell->setValue (Value (str));
00086 }
00087
00088 Value ValueParser::parse (const QString &str)
00089 {
00090 Value val;
00091
00092
00093
00094
00095
00096 if ( str.isEmpty() || str.at(0)=='\'' )
00097 {
00098 val.setValue (str);
00099 return val;
00100 }
00101
00102 bool ok;
00103
00104 QString strStripped = str.stripWhiteSpace();
00105
00106
00107
00108 val = tryParseNumber (strStripped, &ok);
00109 if (ok)
00110 return val;
00111
00112
00113
00114
00115 val = tryParseBool (strStripped, &ok);
00116 if (ok)
00117 return val;
00118
00119
00120
00121 double money = parserLocale->readMoney (strStripped, &ok);
00122 if (ok)
00123 {
00124 val.setValue (money);
00125 val.setFormat (Value::fmt_Money);
00126 return val;
00127 }
00128
00129 val = tryParseDate (strStripped, &ok);
00130 if (ok)
00131 return val;
00132
00133 val = tryParseTime (strStripped, &ok);
00134 if (ok)
00135 return val;
00136
00137
00138 val.setValue (str);
00139 return val;
00140 }
00141
00142 bool ValueParser::tryParseBool (const QString& str, Cell *cell)
00143 {
00144 bool ok;
00145 Value val = tryParseBool (str, &ok);
00146 if (ok)
00147 cell->setValue (val);
00148 return ok;
00149 }
00150
00151 bool ValueParser::tryParseNumber (const QString& str, Cell *cell)
00152 {
00153 bool ok;
00154 Value val = tryParseNumber (str, &ok);
00155 if (ok)
00156 cell->setValue (val);
00157 return ok;
00158 }
00159
00160 bool ValueParser::tryParseDate (const QString& str, Cell *cell)
00161 {
00162 bool ok;
00163 Value value = tryParseDate (str, &ok);
00164 if (ok)
00165 cell->setValue (value);
00166 return ok;
00167 }
00168
00169 bool ValueParser::tryParseTime (const QString& str, Cell *cell)
00170 {
00171 bool ok;
00172 Value value = tryParseTime (str, &ok);
00173 if (ok)
00174 cell->setValue (value);
00175 return ok;
00176 }
00177
00178
00179 Value ValueParser::tryParseBool (const QString& str, bool *ok)
00180 {
00181 Value val;
00182 if (ok) *ok = false;
00183
00184 const QString& lowerStr = str.lower();
00185
00186 if ((lowerStr == "true") ||
00187 (lowerStr == parserLocale->translate("true").lower()))
00188 {
00189 val.setValue (true);
00190 if (ok) *ok = true;
00191 }
00192 else if ((lowerStr == "false") ||
00193 (lowerStr == parserLocale->translate("false").lower()))
00194 {
00195 val.setValue (false);
00196 if (ok) *ok = true;
00197 fmtType = Number_format;
00198 }
00199 return val;
00200 }
00201
00202 double ValueParser::readNumber(const QString &_str, bool * ok, bool * isInt)
00203 {
00204 QString str = _str.stripWhiteSpace();
00205 bool neg = str.find(parserLocale->negativeSign()) == 0;
00206 if (neg)
00207 str.remove( 0, parserLocale->negativeSign().length() );
00208
00209
00210
00211
00212 QString exponentialPart;
00213 int EPos;
00214
00215 EPos = str.find('E', 0, false);
00216
00217 if (EPos != -1)
00218 {
00219 exponentialPart = str.mid(EPos);
00220 str = str.left(EPos);
00221 }
00222
00223 int pos = str.find(parserLocale->decimalSymbol());
00224 QString major;
00225 QString minor;
00226 if ( pos == -1 )
00227 {
00228 major = str;
00229 if (isInt) *isInt = true;
00230 }
00231 else
00232 {
00233 major = str.left(pos);
00234 minor = str.mid(pos + parserLocale->decimalSymbol().length());
00235 if (isInt) *isInt = false;
00236 }
00237
00238
00239 int thlen = parserLocale->thousandsSeparator().length();
00240 int lastpos = 0;
00241 while ( ( pos = major.find( parserLocale->thousandsSeparator() ) ) > 0 )
00242 {
00243
00244 int fromEnd = major.length() - pos;
00245 if ( fromEnd % (3+thlen) != 0
00246 || pos - lastpos > 3
00247 || pos == 0
00248 || (lastpos>0 && pos-lastpos!=3))
00249 {
00250 if (ok) *ok = false;
00251 return 0.0;
00252 }
00253
00254 lastpos = pos;
00255 major.remove( pos, thlen );
00256 }
00257 if (lastpos>0 && major.length()-lastpos!=3)
00258 {
00259 if (ok) *ok = false;
00260 return 0.0;
00261 }
00262
00263 QString tot;
00264 if (neg) tot = '-';
00265
00266 tot += major + '.' + minor + exponentialPart;
00267
00268 return tot.toDouble(ok);
00269 }
00270
00271 Value ValueParser::tryParseNumber (const QString& str, bool *ok)
00272 {
00273 Value value;
00274
00275 bool percent = false;
00276 QString str2;
00277 if( str.at(str.length()-1)=='%')
00278 {
00279 str2 = str.left (str.length()-1).stripWhiteSpace();
00280 percent = true;
00281 }
00282 else
00283 str2 = str;
00284
00285
00286
00287 bool isInt;
00288 double val = readNumber (str2, ok, &isInt);
00289
00290 if (!(*ok))
00291 {
00292 val = str2.toDouble(ok);
00293 if (str.contains('.'))
00294 isInt = false;
00295 else
00296 isInt = true;
00297 }
00298
00299 if (*ok)
00300 {
00301 if (percent)
00302 {
00303
00304
00305 value.setValue (val / 100.0);
00306 value.setFormat (Value::fmt_Percent);
00307 fmtType = Percentage_format;
00308 }
00309 else
00310 {
00311
00312
00313 if (isInt)
00314 value.setValue (static_cast<long> (val));
00315 else
00316 value.setValue (val);
00317
00318 if ( str2.contains('E') || str2.contains('e') )
00319 fmtType = Scientific_format;
00320 else
00321 {
00322 if (val > 1e+10)
00323 fmtType = Scientific_format;
00324 else
00325 fmtType = Number_format;
00326 }
00327 }
00328 }
00329
00330 return value;
00331 }
00332
00333 Value ValueParser::tryParseDate (const QString& str, bool *ok)
00334 {
00335 bool valid = false;
00336 QDate tmpDate = parserLocale->readDate (str, &valid);
00337 if (!valid)
00338 {
00339
00340
00341
00342
00343
00344 QString fmt = parserLocale->dateFormatShort();
00345 int yearPos = fmt.find ("%Y", 0, false);
00346 if ( yearPos > -1 )
00347 {
00348 if ( yearPos == 0 )
00349 {
00350 fmt.remove( 0, 2 );
00351 while ( fmt[0] != '%' )
00352 fmt.remove( 0, 1 );
00353 } else
00354 {
00355 fmt.remove( yearPos, 2 );
00356 for ( ; yearPos > 0 && fmt[yearPos-1] != '%'; --yearPos )
00357 fmt.remove( yearPos, 1 );
00358 }
00359
00360 tmpDate = parserLocale->readDate( str, fmt, &valid );
00361 }
00362 }
00363 if (valid)
00364 {
00365
00366
00367
00368
00369
00370
00371
00372 QString fmt = parserLocale->dateFormatShort();
00373 if( ( fmt.contains( "%y" ) == 1 ) && ( tmpDate.year() > 2999 ) )
00374 tmpDate = tmpDate.addYears( -1900 );
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384 if( ( tmpDate.year() >= 2030 ) && ( tmpDate.year() <= 2069 ) )
00385 {
00386 QString yearFourDigits = QString::number( tmpDate.year() );
00387 QString yearTwoDigits = QString::number( tmpDate.year() % 100 );
00388
00389
00390
00391 if( ( str.contains( yearTwoDigits ) >= 1 ) &&
00392 ( str.contains( yearFourDigits ) == 0 ) )
00393 tmpDate = tmpDate.addYears( -100 );
00394 }
00395
00396
00397 if (parserLocale->formatDate (tmpDate, false) == str)
00398 fmtType = TextDate_format;
00399 else
00400 fmtType = ShortDate_format;
00401 }
00402 if (!valid)
00403 {
00404
00405 tmpDate = QDate::fromString(str,Qt::ISODate);
00406 if (tmpDate.isValid())
00407 {
00408 valid = true;
00409 }
00410 }
00411
00412 if (ok)
00413 *ok = valid;
00414
00415 return Value (tmpDate);
00416 }
00417
00418 Value ValueParser::tryParseTime (const QString& str, bool *ok)
00419 {
00420 if (ok)
00421 *ok = false;
00422
00423 bool valid = false;
00424 bool duration = false;
00425 Value val;
00426
00427 QDateTime tmpTime = readTime (str, true, &valid, duration);
00428 if (!tmpTime.isValid())
00429 tmpTime = readTime (str, false, &valid, duration);
00430
00431 if (!valid)
00432 {
00433 QTime tm;
00434 if (parserLocale->use12Clock())
00435 {
00436 QString stringPm = parserLocale->translate("pm");
00437 QString stringAm = parserLocale->translate("am");
00438 int pos=0;
00439 if((pos=str.find(stringPm))!=-1)
00440 {
00441 QString tmp=str.mid(0,str.length()-stringPm.length());
00442 tmp=tmp.simplifyWhiteSpace();
00443 tm = parserLocale->readTime(tmp+" "+stringPm, &valid);
00444 if (!valid)
00445 tm = parserLocale->readTime(tmp+":00 "+stringPm, &valid);
00446 }
00447 else if((pos=str.find(stringAm))!=-1)
00448 {
00449 QString tmp = str.mid(0,str.length()-stringAm.length());
00450 tmp = tmp.simplifyWhiteSpace();
00451 tm = parserLocale->readTime (tmp + " " + stringAm, &valid);
00452 if (!valid)
00453 tm = parserLocale->readTime (tmp + ":00 " + stringAm, &valid);
00454 }
00455 }
00456 }
00457 if (valid)
00458 {
00459 fmtType = Time_format;
00460 if ( duration )
00461 {
00462 val.setValue (tmpTime);
00463 fmtType = Time_format7;
00464 }
00465 else
00466 val.setValue (tmpTime.time());
00467 }
00468
00469 if (ok)
00470 *ok = valid;
00471
00472 return val;
00473 }
00474
00475 QDateTime ValueParser::readTime (const QString & intstr, bool withSeconds,
00476 bool *ok, bool & duration)
00477 {
00478 duration = false;
00479 QString str = intstr.simplifyWhiteSpace().lower();
00480 QString format = parserLocale->timeFormat().simplifyWhiteSpace();
00481 if ( !withSeconds )
00482 {
00483 int n = format.find("%S");
00484 format = format.left( n - 1 );
00485 }
00486
00487 int days = -1;
00488 int hour = -1, minute = -1;
00489 int second = withSeconds ? -1 : 0;
00490 bool g_12h = false;
00491 bool pm = false;
00492 uint strpos = 0;
00493 uint formatpos = 0;
00494
00495 QDate refDate( 1899, 12, 31 );
00496
00497 uint l = format.length();
00498 uint sl = str.length();
00499
00500 while (l > formatpos || sl > strpos)
00501 {
00502 if ( !(l > formatpos && sl > strpos) )
00503 goto error;
00504
00505 QChar c( format.at( formatpos++ ) );
00506
00507 if (c != '%')
00508 {
00509 if (c.isSpace())
00510 ++strpos;
00511 else if (c != str.at(strpos++))
00512 goto error;
00513 continue;
00514 }
00515
00516
00517 if (sl > strpos && str.at( strpos).isSpace() )
00518 ++strpos;
00519
00520 c = format.at( formatpos++ );
00521 switch (c)
00522 {
00523 case 'p':
00524 {
00525 QString s;
00526 s = parserLocale->translate("pm").lower();
00527 int len = s.length();
00528 if (str.mid(strpos, len) == s)
00529 {
00530 pm = true;
00531 strpos += len;
00532 }
00533 else
00534 {
00535 s = parserLocale->translate("am").lower();
00536 len = s.length();
00537 if (str.mid(strpos, len) == s)
00538 {
00539 pm = false;
00540 strpos += len;
00541 }
00542 else
00543 goto error;
00544 }
00545 }
00546 break;
00547
00548 case 'k':
00549 case 'H':
00550 g_12h = false;
00551 hour = readInt(str, strpos);
00552 if (hour < 0)
00553 goto error;
00554 if (hour > 23)
00555 {
00556 days = (int)(hour / 24);
00557 hour %= 24;
00558 }
00559
00560 break;
00561
00562 case 'l':
00563 case 'I':
00564 g_12h = true;
00565 hour = readInt(str, strpos);
00566 if (hour < 1 || hour > 12)
00567 goto error;
00568
00569 break;
00570
00571 case 'M':
00572 minute = readInt(str, strpos);
00573 if (minute < 0 || minute > 59)
00574 goto error;
00575
00576 break;
00577
00578 case 'S':
00579 second = readInt(str, strpos);
00580 if (second < 0 || second > 59)
00581 goto error;
00582
00583 break;
00584 }
00585 }
00586
00587 if (g_12h)
00588 {
00589 hour %= 12;
00590 if (pm) hour += 12;
00591 }
00592
00593 if (days > 0)
00594 {
00595 refDate.addDays( days );
00596 duration = true;
00597 }
00598
00599 if (ok)
00600 *ok = true;
00601 return QDateTime( refDate, QTime( hour, minute, second ) );
00602
00603 error:
00604 if (ok)
00605 *ok = false;
00606
00607 return QDateTime( refDate, QTime( -1, -1, -1 ) );
00608 }
00609
00616 int ValueParser::readInt (const QString &str, uint &pos)
00617 {
00618 if (!str.at(pos).isDigit())
00619 return -1;
00620 int result = 0;
00621 for ( ; str.length() > pos && str.at(pos).isDigit(); pos++ )
00622 {
00623 result *= 10;
00624 result += str.at(pos).digitValue();
00625 }
00626
00627 return result;
00628 }
00629