#c #string #boost #floating-point
#c #строка #повышение #с плавающей запятой
Вопрос:
Я хочу преобразовать a std::string
, который я прочитал из файла csv, в a float
. Включено несколько представлений с плавающей запятой, таких как:
0,0728239
6.543.584.399
2,67E-02
Все эти строки должны быть плавающими. Сначала я использовал atof()
, но преобразование было неправильным:
2,67E-02 -> 2
6.543.584.399 -> 6.543
Затем я использовал boost::lexical_cast<float>()
, но когда дело доходит до float с включенным показателем, он выдает следующее исключение
`terminate` called after throwing an instance of
`'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::bad_lexical_cast> >'`
`what()`: bad lexical cast: source type value could not be interpreted as target
Aborted
Каков наилучший способ преобразовать все три типа строк в float?
Комментарии:
1. возможно, вы могли бы показать нам пример ввода, показывающий различные случаи?
2. @iam_peter: каков ожидаемый результат?
6.543.584.399
не может быть действительным одновременно с0.0728239
3. Язык — это то, как вы сообщаете C : «Я использую
.
для разделения групп из тысяч и,
для отделения целой части от дробной части». По умолчанию C будет использоватьC locale
, который используется.
для отделения целой части от дробной части и ничего не использует для разделения групп из тысяч. Существует «способ C » использования локалей ( www2.research.att.com /~bs/3rd_loc0.html ), но никто его не использует, а некоторые компиляторы его не реализуют. Однако «способ C» довольно прост.4. @sehe: Неверно для европейских стран. Они поменяли местами наши запятые и десятичные числа в числах.
5. @ iam_peter: черт возьми. конечно 🙂 Это имеет гораздо больше смысла. @MooingDuck: случайно проголосовал за ваш комментарий. Дело в том, что образец был непоследовательным сам по себе. Нет европейской локали, которая поддерживала бы это (OT: я сам из такой европейской страны :))
Ответ №1:
scanf
с правильным набором языковых стандартов. Серьезно. Избавьте себя от необходимости делать это «способом c » в этом случае.
Комментарии:
1.
atof()
вряд ли это «способ C «, и он отлично работает, как только вы устанавливаете текущую локаль.2. Я не ссылался на atof(), но позвольте мне добавить, что я думаю, что scanf — это правильный путь, поскольку atof не сообщает вам, не удалось ли ему проанализировать строку.
3. OP пытался использовать
atof
. Вы критикуете его за то, что он «делает это способом C «. Вы поднимаете хороший вопрос оatof
том, чтобы не сообщать, не удалось ли разобрать строку.
Ответ №2:
http://www.cplusplus.com/reference/clibrary/clocale/
Обратите внимание, что конфигурация локали влияет на поведение многих функций в стандартной библиотеке C: в string.h на функции strcoll и strxfrm влияют правила преобразования символов. В ctype.h на все функции, кроме isdigit и isxdigit, влияет выбранный расширенный набор символов. В stdio.h на форматированные операции ввода / вывода влияют правила преобразования символов и набор символов с десятичной запятой в настройках числового форматирования. В time.h на функцию strftime влияют настройки форматирования времени. В этом заголовке это влияет на значение, возвращаемое его функциями setlocale и localeconv .
http://www.cplusplus.com/reference/clibrary/clocale/setlocale/
setlocale ( LC_NUMERIC, "" ); // "" is the Environment's default locale
Тогда вы сможете правильно использовать atof, scanf и т. Д. Тем не менее, это способ C делать вещи. Способ C заключается в:
float stof(const std::stringamp; input) {
std::stringstream ss;
float resu<
static std::locale uselocale("") //again, "" is Environment's default locale
ss.imbue(uselocale);
ss << input;
ss >> resu<
return resu<
}
Все компиляторы должны принимать эти локали: «», «C»
MSVC принимает эти локали: http://msdn.microsoft.com/en-us/library/hzz3tw78.aspx
(подождите, действительно ли MSVC setlocale
не принимает «en_US»?)
GCC принимает эти локали: http://gcc.gnu.org/onlinedocs/libstdc /manual/localization.html#locale.impl.c
Ответ №3:
Это должно сделать :
#include <sstream>
#include <iostream>
#include <algorithm>
bool isdot(const char amp;c)
{
return '.'==c;
}
float to(std::string s)
{
s.erase(std::remove_if(s.begin(), s.end(), amp;isdot ),s.end());
replace(s.begin(), s.end(), ',', '.');
std::stringstream ss(s);
float v = 0;
ss >> v;
return v;
}
int main()
{
const std::string a1("0,0728239");
const std::string a2("6.543.584.399");
const std::string a3("2,67E-02");
std::cout << to(a1)<<std::endl;
std::cout << to(a2)<<std::endl;
std::cout << to(a3)<<std::endl;
}
Смотрите это в прямом эфире на coliru