【问题标题】:Formatting a string based on Input and predefined values根据输入和预定义值格式化字符串
【发布时间】:2013-05-14 03:35:18
【问题描述】:

我有 26 个值,我认为它们是特殊符号,并且与特殊分隔符“$”一样,值可以从 $A 到 $Z。

同时我有一个预定义的模板:

我有$A,$B,$C.....

现在我允许用户输入一个可以包含特殊符号的字符串以及这些示例的值: 输入 - $ACar $BBike $CTruck。

那么我的输出应该是:*I have Car,Bike,Truck... *

现在所有的特殊符号都被它的值替换了。

注意 1.如果 $A Car $A Bike 是输入值,那么它应该取 $A 因为 Car rest 应该被丢弃。

如果输入字符串不包含任何特殊符号,则输出应该没有变化,输出将是 我有$A,$B,$C.....

3.如果输入以 i am a men $A glass 开头,那么直到 $A 所有值都应该被丢弃。

我应该采用哪种方法来实现这一点?

我正在考虑对输入字符串执行 strstr 并将它们与我的特殊符号进行比较并将特殊符号的位置存储在列表中,然后根据我正在考虑的位置获取值但我不认为它对我有用。

【问题讨论】:

    标签: c string algorithm formatting


    【解决方案1】:

    使用动态字符串简化了处理。

    喜欢这个

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
    
    typedef struct dstr {
        size_t size;
        size_t capacity;
        char *str;
    } Dstr;//dynamic string
    
    Dstr *dstr_make(void){
        Dstr *s;
        s = (Dstr*)malloc(sizeof(Dstr));
        s->size = 0;
        s->capacity=16;
        s->str=(char*)realloc(NULL, sizeof(char)*(s->capacity += 16));
        return s;
    }
    
    void dstr_addchar(Dstr *ds, const char ch){
        ds->str[ds->size] = ch;
        if(++ds->size == ds->capacity)
            ds->str=(char*)realloc(ds->str, sizeof(char)*(ds->capacity += 16));
    }
    
    void dstr_addstr(Dstr *ds, const char *s){
        while(*s) dstr_addchar(ds, *s++);
        //dstr_addchar(ds, '\0');
    }
    
    void dstr_free(Dstr *ds){
        free(ds->str);
        free(ds);
    }
    
    void dic_entry(char *dic[26], const char *source){
        char *p, *backup, ch;
    
        p = backup = strdup(source);
    
        for(;NULL!=(p=strtok(p, " \t\n"));p=NULL){
            if(*p == '$' && isupper(ch=*(p+1))){
                if(dic[ch -'A'] == NULL)
                    dic[ch -'A'] = strdup(p+2);
            }
        }
        free(backup);
    }
    
    void dic_clear(char *dic[26]){
        int i;
        for(i=0;i<26;++i){
            if(dic[i]){
                free(dic[i]);
                dic[i] = NULL;
            }
        }
    }
    
    int main(void){
        const char *template = "I have $A,$B,$C.";
        char *dic[26] = { 0 };
        char buff[1024];
        const char *cp;
        Dstr *ds = dstr_make();
    
        printf("input special value setting: ");
        fgets(buff, sizeof(buff), stdin);
        dic_entry(dic, buff);
    
        for(cp=template;*cp;++cp){
            if(*cp == '$'){
                char ch;
                if(isupper(ch=*(cp+1)) && dic[ch - 'A']!=NULL){
                    dstr_addstr(ds, dic[ch - 'A']);
                    ++cp;
                } else {
                    dstr_addchar(ds, *cp);
                }
            } else {
                dstr_addchar(ds, *cp);
            }
        }
        dstr_addchar(ds, '\0');
        printf("result:%s\n", ds->str);
    
        dic_clear(dic);
        dstr_free(ds);
        return 0;
    }
    /* DEMO
    >a
    input special value setting: $ACar $BBike $CTruck
    result:I have Car,Bike,Truck.
    
    >a
    input special value setting: $BBike
    result:I have $A,Bike,$C.
    */
    

    【讨论】:

    • 上述程序的输出根据输入的值不同,输出应该和对应的值一样。例子——输入字符串为-$ACar $BBike$时输出应该没有区别CPen 或 $CPen $ACar $BBike。这两个输入的 $A,$B,$C 的值是一样的。
    • @Astro 是一样的(不管顺序都是一样的),但也有什么问题?
    • 它应该独立于订单。如果你输入 $AAA$ACAR$BBIKE 那么 $A 的值应该是 AAA 而 $B 应该是 Bike $ACAR 应该被丢弃。在 AAA$ACAR$BBIKE 的情况下 AAA 应该被丢弃。
    • @Astro 我觉得double如果要输入对应的特殊字符是不是错了?但它当然可以改变。
    • 用户可以输入任何内容,甚至可以输入 2,3 或 N 次,但我们需要取第一个值,如果存在特殊符号,则应丢弃其余部分。示例 - 1. $ACar$ABike$BPen 价值 - $A = CAR $B = 笔。 2. $ACar$BPen$ABike $A = 汽车 $B = 自行车
    【解决方案2】:

    您所描述的称为宏处理器宏扩展器

    您可以将符号表存储在由输入字符索引的数组中。

    char *symtab[256] = {0};
    

    由于符号名称是单字母,您可以使用strchr 查找第一个'$' 并检查下一个字符是否为字母(isupper())。

    对于实际的替换,它将需要一些精细的内存管理,除非您只使用非常大的缓冲区并确保只为其提供少量数据。

    如果symtab['A'] == "Car",那么你可以loc = strstr(line, "$A")。那么loc-lineprefix部分的长度,2是被删除的符号名的长度,strlen("Car")是替换的长度,strlen(loc+2)是被删除的长度后缀部分。所以新的字符串大小应该是

    char *result = malloc( (loc-line) - 2 + strlen(symtab['A']) + strlen(loc+2) + 1);
    

    然后修补新的字符串是

    strcpy(result,line);
    strcpy(result + (loc-line), symtab['A']);
    strcpy(result + (loc-line) + strlen(symtab['A']), loc+2);
    

    注意这些是strcpy 不是 strcat 将字符串附加在一起。第二个和第三个strcpy 调用会覆盖刚刚复制的字符串的尾部。

    【讨论】:

    • 我有一个数组,它将特殊符号存储为 **char ar[26][3] ;它的值是 $A,$B .....并且在我正在执行 strstr(line,ar(index),,, 然后将位置保存在列表中的行中。但不确定如何收集值?和在您的算法中,您如何获取特殊符号的实际值?
    • 我会使用常规的 ascii 值进行索引,但这确实会浪费空间。使用您的方式,您必须通过添加和减去 'A' 来转换为/从 ascii 转换。对于收集值,sscanf 应该可以工作。格式类似于:"$%c = %[^$]$%c= %[^$]$%c= %[^$]$%c= %[^$]".
    • 我很困惑。你明白了吗?
    • 我说的是你的算法..从 chaking 下一个字符是 $ 并且下一个是大写 ..直到我们需要检查什么来获取符号的实际值?
    • 好吧,如果你有 char a,b[5],c,d[5],e,f[5];sscanf(inputline,"$%c = %[^$]$%c= %[^$]$%c = %[^$]$%c = %[^$]", &amp;a, b, &amp;c, d, &amp;e, f); 这样的东西,那么你可以使用 symtab[a]=b;symtab[a]=strdup(b); 设置第一个符号。
    猜你喜欢
    • 2018-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-08
    • 1970-01-01
    相关资源
    最近更新 更多