replacing pieces of string

后端 未结 3 1994
星月不相逢
星月不相逢 2021-01-22 18:19

i\'m doing something like excel, i have something like this:

1         2           3
A1        B1          C1

where it replaces the content for

3条回答
  •  北恋
    北恋 (楼主)
    2021-01-22 18:30

    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

    • handroll a (recursive descent) parser
    • use flex/bison (or lex/yacc)

    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.

提交回复
热议问题