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 if (valid)
00456 tmpTime.setTime(tm);
00457 }
00458 }
00459 if (valid)
00460 {
00461 fmtType = Time_format;
00462 if ( duration )
00463 {
00464 val.setValue (tmpTime);
00465 fmtType = Time_format7;
00466 }
00467 else
00468 val.setValue (tmpTime.time());
00469 }
00470
00471 if (ok)
00472 *ok = valid;
00473
00474 return val;
00475 }
00476
00477 QDateTime ValueParser::readTime (const QString & intstr, bool withSeconds,
00478 bool *ok, bool & duration)
00479 {
00480 duration = false;
00481 QString str = intstr.simplifyWhiteSpace().lower();
00482 QString format = parserLocale->timeFormat().simplifyWhiteSpace();
00483 if ( !withSeconds )
00484 {
00485 int n = format.find("%S");
00486 format = format.left( n - 1 );
00487 }
00488
00489 int days = -1;
00490 int hour = -1, minute = -1;
00491 int second = withSeconds ? -1 : 0;
00492 bool g_12h = false;
00493 bool pm = false;
00494 uint strpos = 0;
00495 uint formatpos = 0;
00496
00497 QDate refDate( 1899, 12, 31 );
00498
00499 uint l = format.length();
00500 uint sl = str.length();
00501
00502 while (l > formatpos || sl > strpos)
00503 {
00504 if ( !(l > formatpos && sl > strpos) )
00505 goto error;
00506
00507 QChar c( format.at( formatpos++ ) );
00508
00509 if (c != '%')
00510 {
00511 if (c.isSpace())
00512 ++strpos;
00513 else if (c != str.at(strpos++))
00514 goto error;
00515 continue;
00516 }
00517
00518
00519 if (sl > strpos && str.at( strpos).isSpace() )
00520 ++strpos;
00521
00522 c = format.at( formatpos++ );
00523 switch (c)
00524 {
00525 case 'p':
00526 {
00527 QString s;
00528 s = parserLocale->translate("pm").lower();
00529 int len = s.length();
00530 if (str.mid(strpos, len) == s)
00531 {
00532 pm = true;
00533 strpos += len;
00534 }
00535 else
00536 {
00537 s = parserLocale->translate("am").lower();
00538 len = s.length();
00539 if (str.mid(strpos, len) == s)
00540 {
00541 pm = false;
00542 strpos += len;
00543 }
00544 else
00545 goto error;
00546 }
00547 }
00548 break;
00549
00550 case 'k':
00551 case 'H':
00552 g_12h = false;
00553 hour = readInt(str, strpos);
00554 if (hour < 0)
00555 goto error;
00556 if (hour > 23)
00557 {
00558 days = (int)(hour / 24);
00559 hour %= 24;
00560 }
00561
00562 break;
00563
00564 case 'l':
00565 case 'I':
00566 g_12h = true;
00567 hour = readInt(str, strpos);
00568 if (hour < 1 || hour > 12)
00569 goto error;
00570
00571 break;
00572
00573 case 'M':
00574 minute = readInt(str, strpos);
00575 if (minute < 0 || minute > 59)
00576 goto error;
00577
00578 break;
00579
00580 case 'S':
00581 second = readInt(str, strpos);
00582 if (second < 0 || second > 59)
00583 goto error;
00584
00585 break;
00586 }
00587 }
00588
00589 if (g_12h)
00590 {
00591 hour %= 12;
00592 if (pm) hour += 12;
00593 }
00594
00595 if (days > 0)
00596 {
00597 refDate.addDays( days );
00598 duration = true;
00599 }
00600
00601 if (ok)
00602 *ok = true;
00603 return QDateTime( refDate, QTime( hour, minute, second ) );
00604
00605 error:
00606 if (ok)
00607 *ok = false;
00608
00609 return QDateTime( refDate, QTime( -1, -1, -1 ) );
00610 }
00611
00618 int ValueParser::readInt (const QString &str, uint &pos)
00619 {
00620 if (!str.at(pos).isDigit())
00621 return -1;
00622 int result = 0;
00623 for ( ; str.length() > pos && str.at(pos).isDigit(); pos++ )
00624 {
00625 result *= 10;
00626 result += str.at(pos).digitValue();
00627 }
00628
00629 return result;
00630 }
00631