一、面试中写的代码
主要思路: 把字符串分为 整数、小数、符号三个部分
- 整数部分的规律是: 整数部值 = 整数部值 * 乘值 +当前值 // 整数部分的乘值为10不变
- 小数部分的规律是:小数部分值 = 小数部分 + 当前值 * (小数部分乘值)// 小数部分的值不断缩小10倍
- 符号部分:判断有无’-‘ 存在
// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <stdio.h>
#include <string>
#include <iostream>
using namespace std;
double string_to_double(const std::string &str)
{
double dInteger = 0; // 整数部分
double dDecimal = 0; // 小数部分
int sign = 1; // 符号
bool bFindPoint = false;
double dCount = 1; // 小数部分的值
for (int i = 0 ; i < str.length(); ++i)
{
if (str.at(i) == '-')
{
if (i == 0)
{
sign = -1;
}
else
{
return 0; // error
}
}
else if (str.at(i) == '+')
{
if (i == 0)
{
sign = 1;
}
else
{
return 0; // error
}
}
else if(str.at(i) == '.')
{
if (!bFindPoint)
{
bFindPoint = true;
}
else
{
return 0; // error
}
}
else if (str.at(i) >= '0' && str.at(i) <= '9')
{
if (bFindPoint)
{
dCount *= 0.1;
dDecimal += (dCount * ((int)str.at(i) - '0'));
}
else
{
dInteger *= 10;
dInteger += (int)str.at(i) - '0';
}
}
else
{
return 0; // error
}
}
return sign * (dInteger + dDecimal);
}
int main()
{
std::string str = "-1.23456";
double dValue = string_to_double(str);
std::cout << "string:" << str << std::endl;
std::cout << "double:" << dValue << std::endl;
system("pause");
return 0;
}
二、标准库代码
经过网上查阅资料才知道,字符串存放double值有很多写法类似:科学计数法、不同进制、三位间隔符(不同的地区 不同的国家 不一样)等等,譬如”123 000 157 100″ “123,000,157,100” “1.03E+08” “0x15”
- 第一步:把收到的字符串格式化为本地C语言表达形式
- 第二步:把格式化后的字符串转化为double
Qt 源码
double asciiToDouble(const char *num, int numLen, bool &ok, int &processed,
TrailingJunkMode trailingJunkMode)
{
// 字符不能为空
if (*num == '\0')
{
ok = false;
processed = 0;
return 0.0;
}
ok = true;
// 优先处理未定义或不可表示的值--类似 -1开根号
if (qstrcmp(num, "nan") == 0)
{
processed = 3;
return qt_snan();
}
else if ((num[0] == '-' || num[0] == '+') && qstrcmp(num + 1, "nan") == 0)
{
processed = 0;
ok = false;
return 0.0;
}
// 超出浮点数的表示范围
if (qstrcmp(num, "+inf") == 0)
{
processed = 4;
return qt_inf();
}
else if (qstrcmp(num, "inf") == 0)
{
processed = 3;
return qt_inf();
}
else if (qstrcmp(num, "-inf") == 0)
{
processed = 4;
return -qt_inf();
}
double d = 0.0;
#if !defined(QT_NO_DOUBLECONVERSION) && !defined(QT_BOOTSTRAPPED)
int conv_flags = (trailingJunkMode == TrailingJunkAllowed) ?
double_conversion::StringToDoubleConverter::ALLOW_TRAILING_JUNK :
double_conversion::StringToDoubleConverter::NO_FLAGS;
double_conversion::StringToDoubleConverter conv(conv_flags, 0.0, qt_snan(), 0, 0);
d = conv.StringToDouble(num, numLen, &processed);
if (!qIsFinite(d))
{
ok = false;
if (qIsNaN(d))
{
// Garbage found. We don't accept it and return 0.
processed = 0;
return 0.0;
} else {
// Overflow. That's not OK, but we still return infinity.
return d;
}
}
#else
if (qDoubleSscanf(num, QT_CLOCALE, "%lf%n", &d, &processed) < 1)
processed = 0;
if ((trailingJunkMode == TrailingJunkProhibited && processed != numLen) || qIsNaN(d))
{
// Implementation defined nan symbol or garbage found. We don't accept it.
processed = 0;
ok = false;
return 0.0;
}
if (!qIsFinite(d))
{
// Overflow. Check for implementation-defined infinity symbols and reject them.
// We assume that any infinity symbol has to contain a character that cannot be part of a
// "normal" number (that is 0-9, ., -, +, e).
ok = false;
for (int i = 0; i < processed; ++i)
{
char c = num[i];
if ((c < '0' || c > '9') && c != '.' && c != '-' && c != '+' && c != 'e')
{
// Garbage found
processed = 0;
return 0.0;
}
}
return d;
}
#endif // !defined(QT_NO_DOUBLECONVERSION) && !defined(QT_BOOTSTRAPPED)
// Otherwise we would have gotten NaN or sorted it out above.
Q_ASSERT(trailingJunkMode == TrailingJunkAllowed || processed == numLen);
// Check if underflow has occurred.
if (isZero(d))
{
for (int i = 0; i < processed; ++i)
{
if (num[i] >= '1' && num[i] <= '9')
{
// if a digit before any 'e' is not 0, then a non-zero number was intended.
ok = false;
return 0.0;
}
else if (num[i] == 'e' || num[i] == 'E')
{
break;
}
}
}
return d;
}
// 格式化字符串---转化为本地C语言表达形式
bool QLocaleData::numberToCLocale(const QChar *str, int len, QLocale::NumberOptions number_options,
CharBuff *result) const
{
const QChar *uc = str;
int l = len;
int idx = 0;
// 跳过空格键
while (idx < l && uc[idx].isSpace())
{
++idx;
}
if (idx == l) // 字符串为空 或者 全部为空格
{
return false;
}
// 此时的idx 为第一个不为空格的位置
// 检查尾部的空格数
for (; idx < l; --l)
{
if (!uc[l - 1].isSpace())
{
break;
}
}
// 此时的l为从后向前第一个不为空格的位置
// idx---------l 为起始不为空和结尾不为空的标志位
int group_cnt = 0; // 分组符号的个数
int decpt_idx = -1; // 小数点的位置
int last_separator_idx = -1; // 上一个分组符号的位置
int start_of_digits_idx = -1; // 数字起始位
int exponent_idx = -1; // e的位置
while (idx < l)
{
const QChar in = uc[idx];
char out = digitToCLocale(in); // 把单个字符转化为本地c语言表达形式
if (out == 0) // 字符0标识空字符--当前表示为digitToCLocale未识别到的字符
{
if (in == m_list)
{
out = ';';
}
else if (in == m_percent)
{
out = '%';
}
// for handling base-x numbers
else if (in.unicode() >= 'A' && in.unicode() <= 'Z') // 不同进制
{
out = in.toLower().toLatin1();
}
else if (in.unicode() >= 'a' && in.unicode() <= 'z')
{
out = in.toLatin1();
}
else // 错误字符
{
break;
}
}
else if (out == '.') // 小数点
{
// 如果多于一个小数点或e后的点则转化失败
if (decpt_idx != -1 || exponent_idx != -1)
{
return false;
}
decpt_idx = idx;
}
else if (out == 'e' || out == 'E') // e的位置
{
exponent_idx = idx;
}
if (number_options & QLocale::RejectLeadingZeroInExponent)
{
// 如果存在指数位、且当前的字符不被digitToCLocale识别、且当前不是最后一个字符
if (exponent_idx != -1 && out == '0' && idx < l - 1)
{
// 指数后面只能为 '+' '-' '0'~'9' 否则就是错误
if (result->last() < '0' || result->last() > '9')
{
return false;
}
}
}
if (number_options & QLocale::RejectTrailingZeroesAfterDot)
{
// If we've seen a decimal point and the last character after the exponent is 0, then
// that is a trailing zero.
if (decpt_idx >= 0 && idx == exponent_idx && result->last() == '0')
{
return false;
}
}
if (!(number_options & QLocale::RejectGroupSeparator))
{
if (start_of_digits_idx == -1 && out >= '0' && out <= '9') // 数字起始位
{
start_of_digits_idx = idx;
}
else if (out == ',')
{
// 小数点后不允许组字符存在----类似于 123 234 564 或者 123,234,564 或者123;234;564 等' ' ',' ';' 被称为组字符
if (decpt_idx != -1 || exponent_idx != -1)
{
return false;
}
// 检查上一个分组符号、和当前的差值--存在部分语言不允许分组https://en.wikipedia.org/wiki/Thousands_separator
if (last_separator_idx != -1 && idx - last_separator_idx != 4)
{
return false;
}
// 如果当前是第一个分租符 且前面没出现数字、或者数字的个数不为3 则分组失败
if (last_separator_idx == -1 && (start_of_digits_idx == -1 || idx - start_of_digits_idx > 3))
{
return false;
}
last_separator_idx = idx;
++group_cnt;
// don't add the group separator
++idx;
continue;
}
else if (out == '.' || out == 'e' || out == 'E')
{
// 检查上一个分组符号、和当前的差值--存在部分语言不允许分组https://en.wikipedia.org/wiki/Thousands_separator
if (last_separator_idx != -1 && idx - last_separator_idx != 4)
{
return false;
}
// 不再处理分租符
last_separator_idx = -1;
}
}
result->append(out);
++idx;
} // end while
// 处理完毕后(或者是break了),判断下 当前位置和分组符位置是否符合要求
if (!(number_options & QLocale::RejectGroupSeparator))
{
// group separator post-processing
// did we end in a separator?
if (last_separator_idx + 1 == idx)
{
return false;
}
// 数字个数不够-- 类似于:123,254,2
if (last_separator_idx != -1 && idx - last_separator_idx != 4)
{
return false;
}
}
if (number_options & QLocale::RejectTrailingZeroesAfterDot)
{
// In decimal form, the last character can be a trailing zero if we've seen a decpt.
if (decpt_idx != -1 && exponent_idx == -1 && result->last() == '0')
{
return false;
}
}
// 结尾符
result->append('\0');
return idx == l;
}
double QLocaleData::stringToDouble(const QChar *begin, int len, bool *ok,
QLocale::NumberOptions number_options) const
{
CharBuff buff;
// 格式化
if (!numberToCLocale(begin, len, number_options, &buff)) {
if (ok != 0)
*ok = false;
return 0.0;
}
int processed = 0;
bool nonNullOk = false;
// 计算值
double d = asciiToDouble(buff.constData(), buff.length() - 1, nonNullOk, processed);
if (ok)
*ok = nonNullOk;
return d;
}
// 把单个字符转化为本地c语言表达形式
inline char QLocaleData::digitToCLocale(QChar in) const
{
const ushort tenUnicode = m_zero + 10;
if (in.unicode() >= m_zero && in.unicode() < tenUnicode)
return '0' + in.unicode() - m_zero;
if (in.unicode() >= '0' && in.unicode() <= '9') // 数据字符
return in.toLatin1();
if (in == m_plus || in == QLatin1Char('+'))
return '+';
if (in == m_minus || in == QLatin1Char('-') || in == QChar(0x2212)) // 0x2212 Unicode 字符'−'
return '-';
if (in == m_decimal) // 小数点
return '.';
if (in == m_group) // 间隔符
return ',';
if (in == m_exponential || in == QChar::toUpper(m_exponential)) // e
return 'e';
// In several languages group() is the char 0xA0, which looks like a space.
// People use a regular space instead of it and complain it doesn't work.
if (m_group == 0xA0 && in.unicode() == ' ') // 0xA0表示汉字的开始
return ',';
return 0;
}