/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
double ScGlobal::ConvertStringToValue( const OUString& rStr, const ScCalcConfig& rConfig,
FormulaError & rError, FormulaError nStringNoValueError,
ScInterpreterContext& rContext, SvNumFormatType & rCurFmtType )
{ // We keep ScCalcConfig::StringConversion::LOCALE default until // we provide a friendly way to convert string numbers into numbers in the UI.
double fValue = 0.0; if (nStringNoValueError == FormulaError::CellNoValue)
{ // Requested that all strings result in 0, error handled by caller.
rError = nStringNoValueError; return fValue;
}
switch (rConfig.meStringConversion)
{ case ScCalcConfig::StringConversion::ILLEGAL:
rError = nStringNoValueError; return fValue; case ScCalcConfig::StringConversion::ZERO: return fValue; case ScCalcConfig::StringConversion::LOCALE:
{ if (rConfig.mbEmptyStringAsZero)
{ // The number scanner does not accept empty strings or strings // containing only spaces, be on par in these cases with what was // accepted in OOo and is in AOO (see also the // StringConversion::UNAMBIGUOUS branch) and convert to 0 to prevent // interoperability nightmares.
if (isEmptyString( rStr)) return fValue;
}
sal_uInt32 nFIndex = 0; if (!rContext.NFIsNumberFormat(rStr, nFIndex, fValue))
{
rError = nStringNoValueError;
fValue = 0.0;
} return fValue;
} break; case ScCalcConfig::StringConversion::UNAMBIGUOUS:
{ if (!rConfig.mbEmptyStringAsZero)
{ if (isEmptyString( rStr))
{
rError = nStringNoValueError; return fValue;
}
}
} // continue below, pulled from switch case for better readability break;
}
rtl_math_ConversionStatus eStatus;
sal_Int32 nParseEnd; // Decimal and group separator 0 => only integer and possibly exponent, // stops at first non-digit non-sign.
fValue = ::rtl::math::stringToDouble( rStr, 0, 0, &eStatus, &nParseEnd);
sal_Int32 nLen = rStr.getLength(); if (eStatus == rtl_math_ConversionStatus_Ok && nParseEnd < nLen)
{ // Not at string end, check for trailing blanks or switch to date or // time parsing or bail out. const sal_Unicode* const pStart = rStr.getStr(); const sal_Unicode* p = pStart + nParseEnd; const sal_Unicode* const pStop = pStart + nLen; switch (*p++)
{ case' ': while (p < pStop && *p == ' ')
++p; if (p < pStop)
rError = nStringNoValueError; break; case'-': case':':
{ bool bDate = (*(p-1) == '-'); enum State { year = 0, month, day, hour, minute, second, fraction, done, blank, stop };
sal_Int32 nUnit[done] = {0,0,0,0,0,0,0}; const sal_Int32 nLimit[done] = {0,12,31,0,59,59,0};
State eState = (bDate ? month : minute);
rCurFmtType = (bDate ? SvNumFormatType::DATE : SvNumFormatType::TIME);
nUnit[eState-1] = o3tl::toInt32(rStr.subView( 0, nParseEnd)); const sal_Unicode* pLastStart = p; // Ensure there's no preceding sign. Negative dates // currently aren't handled correctly. Also discard // +CCYY-MM-DD
p = pStart; while (p < pStop && *p == ' ')
++p; if (p < pStop && !rtl::isAsciiDigit(*p))
rError = nStringNoValueError;
p = pLastStart; while (p < pStop && rError == FormulaError::NONE && eState < blank)
{ if (eState == minute)
rCurFmtType |= SvNumFormatType::TIME; if (rtl::isAsciiDigit(*p))
{ // Maximum 2 digits per unit, except fractions. if (p - pLastStart >= 2 && eState != fraction)
rError = nStringNoValueError;
} elseif (p > pLastStart)
{ // We had at least one digit. if (eState < done)
{
nUnit[eState] = o3tl::toInt32(rStr.subView( pLastStart - pStart, p - pLastStart)); if (nLimit[eState] && nLimit[eState] < nUnit[eState])
rError = nStringNoValueError;
}
pLastStart = p + 1; // hypothetical next start // Delimiters must match, a trailing delimiter // yields an invalid date/time. switch (eState)
{ case month: // Month must be followed by separator and // day, no trailing blanks. if (*p != '-' || (p+1 == pStop))
rError = nStringNoValueError; break; case day: if ((*p != 'T' || (p+1 == pStop)) && *p != ' ')
rError = nStringNoValueError; // Take one blank as a valid delimiter // between date and time. break; case hour: // Hour must be followed by separator and // minute, no trailing blanks. if (*p != ':' || (p+1 == pStop))
rError = nStringNoValueError; break; case minute: if ((*p != ':' || (p+1 == pStop)) && *p != ' ')
rError = nStringNoValueError; if (*p == ' ')
eState = done; break; case second: if (((*p != ',' && *p != '.') || (p+1 == pStop)) && *p != ' ')
rError = nStringNoValueError; if (*p == ' ')
eState = done; break; case fraction:
eState = done; break; default:
rError = nStringNoValueError; break;
}
eState = static_cast<State>(eState + 1);
} else
rError = nStringNoValueError;
++p;
} if (eState == blank)
{ while (p < pStop && *p == ' ')
++p; if (p < pStop)
rError = nStringNoValueError;
eState = stop;
}
// Month without day, or hour without minute. if (eState == month || (eState == day && p <= pLastStart) ||
eState == hour || (eState == minute && p <= pLastStart))
rError = nStringNoValueError;
if (rError == FormulaError::NONE)
{ // Catch the very last unit at end of string. if (p > pLastStart && eState < done)
{
nUnit[eState] = o3tl::toInt32(rStr.subView( pLastStart - pStart, p - pLastStart)); if (nLimit[eState] && nLimit[eState] < nUnit[eState])
rError = nStringNoValueError;
} if (bDate && nUnit[hour] > 23)
rError = nStringNoValueError; if (rError == FormulaError::NONE)
{ if (bDate && nUnit[day] == 0)
nUnit[day] = 1; double fFraction = (nUnit[fraction] <= 0 ? 0.0 :
::rtl::math::pow10Exp( nUnit[fraction], static_cast<int>( -ceil( log10( static_cast<double>( nUnit[fraction])))))); if (!bDate)
fValue = 0.0; else
{
Date aDate(
sal::static_int_cast<sal_Int16>(nUnit[day]),
sal::static_int_cast<sal_Int16>(nUnit[month]),
sal::static_int_cast<sal_Int16>(nUnit[year])); if (!aDate.IsValidDate())
rError = nStringNoValueError; else
{
fValue = aDate - rContext.NFGetNullDate();
}
}
fValue += ((nUnit[hour] * 3600) + (nUnit[minute] * 60) + nUnit[second] + fFraction) / 86400.0;
}
}
} break; default:
rError = nStringNoValueError;
} if (rError != FormulaError::NONE)
fValue = 0.0;
} return fValue;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.