Преобразовать строку в число

Я ищу способ взять строку и проверить 3 возможности.

  • Digit и, таким образом, преобразует его в подписанный int (не длинный)
  • Является символьным представлением, ранее определенным во время выполнения, и преобразует его в целое число со знаком.
  • Ни один

«Символическое представление» будет в основном похоже на ассоциативный массив, который начинается с 0 элементов и расширяется по мере добавления новых символов. Например, скажем, например, что у C были ассоциативные массивы (я бы хотел) с этим peusdocode:

symbol_array['q'] = 3;
symbol_array['five'] = 5;
symbol_array['negfive'] = -5;
symbol_array['random294'] = 28;

signed int i;
string = get_from_input();
if(!(i = convert_to_int(string))) {
    if(!(i = translate_from_symbol(string))) {
        printf("Invalid symbol or integer\n");
        exit(1);
    }
}

printf("Your number: %d\n, i);

Идея заключалась в том, что если бы они ввели «5», они преобразовали бы его в 5 с помощью convert_to_int, а если бы они ввели «пять», они бы преобразовали его в 5 с помощью translate_from_symbol. Что, по моему мнению, может быть самым сложным, так это то, что если бы они ввели «random294», это преобразовало бы его не в 294, а в 28. Если бы они ввели «foo», то он вышел бы (1).

Мои общие вопросы таковы: (Вместо того, чтобы делать несколько сообщений)

При создании convert_to_int я знаю, что не должен использовать atoi, потому что он не ошибается. Некоторые люди говорят, что нужно использовать strtol, но кажется утомительным преобразовывать его обратно в недлинный int. Упрощенный (читай: кратчайший) способ, который я нашел, использует sscanf:

int i;
if ((sscanf(string, "%d", &i)) == 1){
    return i;
}

Однако некоторые люди смотрят на это даже свысока. Какой метод лучше, если не sscanf или преобразование strtol?

Во-вторых, как я могу не только вернуть целое число, но и узнать, нашел ли он его. Например, если пользователь ввел «0», то он вернет 0, таким образом установив FALSE в моем выражении if. Я думал об использовании -1, если он не найден, но, поскольку я возвращаю подписанные целые числа, это также страдает от той же проблемы. В PHP я знаю, например, что с strpos они используют === FALSE

Наконец, есть ли короткий код, который эмулирует ассоциированные массивы и/или позволяет добавлять элементы в массив во время выполнения?


person user3196590    schedule 15.01.2014    source источник


Ответы (2)


Во-первых, вы можете пересмотреть свой синтаксис и установить ключевое слово отдельно от операнда, то есть "neg five" вместо "negfive". В противном случае ваш поиск символов для ключевых слов должен учитывать каждый префикс. ("random294" может подойти, если в ваших ключевых словах не разрешено использовать цифры.)

Конечно, sscanf сообщает вам, нашли ли вы десятичное число в возвращаемом значении, и записывает это десятичное число в отдельный int, что хорошо, но вам придется следить за конечными символами, проверяя, что количество прочитанных символов равно длине ваша строка в формате %n. В противном случае sscanf будет считать 5x допустимым десятичным числом. strtol также возвращает указатель на позицию после проанализированного десятичного числа, но, на мой взгляд, слишком сильно зависит от проверки err.

Тот факт, что strtol использует длинные целые числа, не должен быть проблемой. Если ввод не соответствует типу int, верните INT_MAX или INT_MIN или выдайте ошибку.

Вы также можете легко написать функцию-оболочку вокруг sscanf или strtol, которая лучше соответствует вашим потребностям. (Я знаю, что мне нужна функция, которая возвращает true в случае успеха и сохраняет целое число с помощью аргумента указателя в стиле sscanf, где успех означает отсутствие завершающих нецифровых символов.)

Наконец, об ассоциативных массивах: нет короткого кода, по крайней мере, в C. Вам придется реализовать свою собственную хеш-карту или использовать библиотеку. В качестве первого наброска я бы использовал линейный список строк и проверял их одну за другой. Это очень наивный подход, но его легко реализовать. Я предполагаю, что вы не начинаете с большого количества символов и не выполняете много проверок, поэтому скорость не должна быть проблемой. (Вы можете отсортировать массив и использовать бинарный поиск, чтобы ускорить его, но вам придется повторно сортировать после каждой вставки.) Когда у вас есть работающая логика вашей программы, вы можете начать думать о хэш-картах.

person M Oehm    schedule 15.01.2014

Что-то вроде этого должно выполнять вашу работу:

#include <stdio.h>
#include <string.h>

struct StringToLongLookUp {
    char *str;
    char *num;
};

struct StringToLongLookUp table[] =
{
    { "q"        ,  "3" },
    { "five"     ,  "5" },
    { "negfive"  , "-5" },
    { "random294", "28" }
};


int translate_from_symbol(char **str)
{
    int i;
    for(i = 0; i < (sizeof(table) / sizeof(struct StringToLongLookUp)); i++)
    {
        if(strcmp(*str, table[i].str) == 0)
        {                
            *str = table[i].num;
            return 1; // TRUE
        }
    }
    return 0; // FALSE
}

int main()
{

    char buf[100];
    char *in = buf;
    char *out;
    int val;

    scanf("%s", in);

    translate_from_symbol(&in);

    val = strtol(in, &out, 10);

    if (in != out)
    {            
        printf("\nValue = %d\n", val);
    }
    else
    {
        printf("\nValue Invalid\n");
    }
}

Конечно, вы получите long, но преобразование его в int не должно быть проблемой, как упоминалось выше.

person th33lf    schedule 21.01.2014