Преобразовать строку в float в c

#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