user3196590
user3196590

Reputation: 1

Translate string to number

I am looking for a way to take a string and check 3 possibilities.

The "symbolic representation" will be basically like an associative array that starts at 0 elements and expands as more symbols are added. For example lets say for instance that C had associative arrays (I wish) with this 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);

The idea being if they entered "5" it would convert it to 5 via convert_to_int, and if they entered "five" it would convert it to 5 via translate_from_symbol. As what I feel may be hardest is if they entered "random294" it wouldn't convert it to 294, but to 28. If they entered "foo" then it would exit(1).

My general questions are these: (Instead of making multiple posts)

When making convert_to_int I know I shouldn't use atoi because it doesn't fail right. Some people say to use strtol but it seems tedious to convert it back to a non-long int. The simplistic (read: shortest) way I've found is using sscanf:

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

However, some people look down on that even. What is a better method if not sscanf or converting strtol?

Secondly, how can I not only return an integer but also know if it found one. For example if the user entered "0" then it would return 0, thus setting off my FALSE in my if statement. I had considered using -1 if not found but since I am returning signed int's then this also suffers from the same problem. In PHP I know for example with strpos they use === FALSE

Finally, is there any short code that emulates associate arrays and/or lets me push elements on to the array in runtime?

Upvotes: 0

Views: 151

Answers (2)

th33lf
th33lf

Reputation: 2275

Something like this should do your job:

#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");
    }
}

Of course, you get a long, but converting that to int shouldn't be an issue as mentioned above.

Upvotes: 0

M Oehm
M Oehm

Reputation: 29126

First, you might want to revise your syntax and set the keyword apart from the operand, i.e. "neg five" instead of "negfive". Otherwise your symbol lookup for the keywords has to consider every prefix. ("random294" might be okay if your keywords aren't allowed to have digits in them.)

Sure, sscanf tells you whether you found a decimal in the return value and writes that decimal to a separate int, which is nice, but you'll have to watch out for trailing characters by checking that the number of characters read equals the length of your string with the %n format. Otherwise, sscanf will consider 5x as legal decimal number. strtol also returns a pointer to the location after the parsed decimal number, but it relies too much on checking err for my taste.

The fact that strtol uses long integers shouldn't be an issue. If the input doesn't fit into an int, return INT_MAX or INT_MIN or issue an error.

You can also easily write a wrapper function around sscanf or strtol that suits your needs better. (I know I'd like a function that returns true on success and stores the integer via a pointer argument, sscanf style, where success means: no trailing non-digit characters.)

Finally, about the associative arrays: There is no short code, at least not in C. You'll have to implement your own hash map or use a library. As a first draft, I'd use a linear list of strings and check them one by one. This is a very naive approach, but easy to implement. I assume that you don't start out with a lot of symbols, and you're not doing a lot of checks, so speed shouldn't be an issue. (You can sort the array and use binary search to speed it up, but you'd have to re-sort after every insertion.) Once you have the logic of your program working, you can start thinking about hash maps.

Upvotes: 1

Related Questions