i\'m doing something like excel, i have something like this:
1 2 3
A1 B1 C1
where it replaces the content for
You might just reuse this c++ solution (replacing the generic iterators by hardcoding char*
instead).
I gave it a whirl. However, I wish to give a warning: it looks like you're trying to implement an expression parser. I'd strongly advise you to either
so you don't paint yourself in an awkward corner of error-prone text-handling in C.
Edit: I rewrote your C program using C++; you can see it working live here.
Edit 2: Another fixup of your C program in pure C: http://ideone.com/ExnufJ updated to support iterative expansions now, too
The answer just concerns itself with the pure C approach:
So, let's get started. I assumed a sample "spreadsheet" (it could contain numbers instead of strings):
const char* cells[][4] = {
/* A B C D */
{ "the" , "lazy" , "cow" , "jumped" }, /* 1 */
{ "over" , "the" , "quick", "brown" }, /* 2 */
{ "paper", "packages", "tied" , "up" }, /* 3 */
{ "with" , "silver" , "white", "winters" }, /* 4 */
{ "that" , "melt" , "fox" , "springs" }, /* 5 */
};
Using just two helpers:
const char* get_cell_value(const char* coordinate_b, const char* coordinate_e);
char* expand_cell_references(const char* f, const char* const l, char* o); /*the magic engine*/
we can write the following demo program:
int main()
{
const char in[] = "The C2 D2 C5 D1 A2 B2 B1 dog!";
char out[1024] = {0};
expand_cell_references(in, in+strlen(in), out);
puts(out); /* "The quick brown fox jumped over the lazy dog!" */
return 0;
}
which prints the well-known test phrase as per the comment. Now, get_cell_value
is really simple:
const char* get_cell_value(const char* coordinate_b, const char* coordinate_e)
{
size_t col = 0, row = 0;
const char* it;
for (it=coordinate_b; it != coordinate_e; ++it)
{
if (*it >= 'A' && *it <= 'Z')
col = 26*col + (*it - 'A');
if (*it >= '0' && *it <= '9')
row = 10*row + (*it - '0'); /* or use atoi and friends */
}
row--; /* 1-based row nums in Excel */
return cells[row][col]; /* 1-based indexes in Excel */
}
And expand_cell_references
is slightly more involved, being a simple DFA parser:
char* expand_cell_references(const char* f, const char* const l, char* o)
{
enum parser_state {
other,
in_coord_col,
in_coord_row
} state = other;
/*temporary storage for coordinates being parsed:*/
char accum[16] = {0};
char* accit = accum;
while (f!=l)
{
switch(state) /*dummy, the transitions flow in fallthrough order for now*/
{
case other:
*(accit = accum) = 0; /*reset the accumulator*/
while (f!=l && !(*f>='A' && *f<='Z'))
*o++ = *f++;
/*fallthrough*/
case in_coord_col:
while (f!=l && *f>='A' && *f<='Z')
*accit++ = *f++;
/*fallthrough*/
case in_coord_row:
{
const char* expanded = accum;
if (f!=l && *f>='0' && *f<='9')
{
while (f!=l && *f>='0' && *f<='9')
*accit++ = *f++;
expanded = get_cell_value(accum, accit);
}
else
{
*accit = 0;
}
while (*expanded)
*o++ = *expanded++;
continue; /*state = other;*/
}
}
}
return o;
}
I took some shortcuts there, because this grammar is so minimalist, but it should give you a proper idea of where to start.
See a live demo here http://ideone.com/kS7XqB so you can play with it yourself. Note that I added debugging (asserts) to the
get_cell_value
function so you don't accidentally reference out-of-bounds indexes.
I think that as may be replaced with values by table lookup by cutting the name simply its corresponding value in the name of the string you want to replace.
E.g
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct pair {
char key[16];
int value;
} Pair;
int main(void){
Pair var_table[] = { { "A1", 1 }, {"B1", 2}, { "C1", 3 }};//sorted
size_t size = sizeof(var_table)/sizeof(*var_table);
char input[256] = "A1+B1+C1";
char outbuff[4096];
char *p;
int offset = 0;
printf("This -> %s\n\n", input);
for(p=input;*p;){
Pair *var;
char op, *opp;
opp=strpbrk(p, "+-*/");
if(opp){
op = *opp;
*opp = '\0';//cut string at op position
}
//search key(p)
var = (Pair*)bsearch(p, var_table, size, sizeof(*var), (int (*)(const void *, const void *))strcmp);
if(var)//find!
offset += sprintf(outbuff + offset, "%d", var->value);//or store array?
else
offset += sprintf(outbuff + offset, "%s", "#UNKNOWN_VAR_NAME#");
if(opp){
offset += sprintf(outbuff + offset, "%c", op);
p = opp + 1;
} else
break;
}
printf("to -> %s\n", outbuff);
return 0;
}
Any time you run into some string manipulation problem in C, your first instinct should be to look at string.h
and see what's available there. As outlined in several answers here, there is no function to do string replacement directly, but it should be possible to use strstr
and strncpy
to find occurrences of substrings and then copy the replacement (into a new buffer so as not to clobber the rest of the original, obviously).