一尘不染

将az扩展为abc…xyz形式的方法

algorithm

嗨:)我想做的是编写一个简单的程序以从最短的入口开始扩展

例如

az或0-9或abc或a-z0-9

最长写

例如

abc … xyz或0123456789或abc或abcdefghijklmnouprstwxyz0123456789

第一个示例最短条目=第一个示例结果,应给出:)

到目前为止,我写这样的东西,它只适用于从a到z的字母:

expand(char s[])
{
   int i,n,c;
   n=c=0;
   int len = strlen(s);
   for(i = 1;s[i] > '0' && s[i]<= '9' || s[i] >= 'a' && s[i] <= 'z' || s[i]=='-';i++)
   {
      /*c = s[i-1];
      g = s[i];
      n = s[i+1];*/
      if( s[0] == '-')
          printf("%c",s[0]);
      else if(s[i] == '-')
      {
         if(s[i-1]<s[i+1])
         {
             while(s[i-1] <= s[i+1])
             {
                 printf("%c", s[i-1]);
                 s[i-1]++;
             }
         }
         else if(s[i-1] == s[i+1])
             printf("%c",s[i]);
         else if(s[i+1] != '-')
             printf("%c",s[i]);
         else if(s[i-1] != '-')
             printf("%c",s[i]);
    }
    else if(s[i] == s[i+1])
    {

      while(s[i] == s[i+1])
      {
           printf("%c",s[i]);
           s[i]++;
      }
    }
    else if( s[len] == '-')
         printf("%c",s[len]);
 }

}

但现在我被卡住了:(

任何想法,我应该检查我的程序正常工作吗?

编辑1: @Andrew Kozak(1)abcd(2)01234

感谢您的提前:)


阅读 167

收藏
2020-07-28

共1个答案

一尘不染

完整的测试程序,包括您的测试用例,地雷和一些酷刑测试,可以在http://ideone.com/sXM7b#info_3915048上实时查看。

基本原理

我敢肯定我夸大了要求,但是

  • 这应该是如何以健壮的方式进行解析的一个很好的例子
    • 以显式方式使用状态
    • 验证输入(!)
    • 这个版本没有假设a-c-b不会发生
    • 在“ Hello World”(或(char*) 0)之类的简单输入上,它也不会窒息甚至失败
  • 它显示了如何在printf("%c", c)不使用外部功能的情况下避免使用每个字符。
  • 我发表了一些评论来解释为什么会发生什么,但是总的来说,您会发现该代码无论如何都更加清晰易读

    • 远离太多的短名称变量
    • 使用不透明的索引器避免复杂的条件
    • 避免整个字符串长度的事务:我们只需要2个字符的最大前行,*it=='-'或者如果为空字符,则or predicate(*it)只会返回 false 快捷方式评估使 我们无法访问过去的输入字符
    • 一个警告:我 尚未 对输出缓冲区溢出实施适当的检查(容量硬编码为2048个字符)。我把它留给 读者看 是众所周知的 练习

最后但并非最不重要的是,我 这样做 的原因:

  • 既然它们执行等效的功能,它将使我能够比较C 版本和C版本的原始性能。 _现在,我完全希望C版本在某种程度上胜过C (让我们猜测:4倍?),但是,让我们再次看看GNU编译器为我们提供了哪些惊喜。 更多后来_ 更新 发现我离不远:github(代码和结果)

纯C实现

事不宜迟,实现包括测试用例:

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

int alpha_range(char c) { return (c>='a') && (c<='z'); }
int digit_range(char c) { return (c>='0') && (c<='9'); }

char* expand(const char* s)
{
    char buf[2048];

    const char* in  = s;
          char* out = buf;

    // parser state
    int (*predicate)(char) = 0; // either: NULL (free state), alpha_range (in alphabetic range), digit_range (in digit range)
    char lower=0,upper=0;       // tracks lower and upper bound of character ranges in the range parsing states

    // init
    *out = 0;

    while (*in)
    {
        if (!predicate)
        {
            // free parsing state
            if (alpha_range(*in) && (in[1] == '-') && alpha_range(in[2]))
            {
                lower = upper = *in++;
                predicate = &alpha_range;
            }
            else if (digit_range(*in) && (in[1] == '-') && digit_range(in[2]))
            {
                lower = upper = *in++;
                predicate = &digit_range;
            } 
            else *out++ = *in;
        } else
        { 
            // in a range
            if (*in < lower) lower = *in;
            if (*in > upper) upper = *in;

            if (in[1] == '-' && predicate(in[2])) 
                in++; // more coming
            else
            {
                // end of range mode, dump expansion
                char c;
                for (c=lower; c<=upper; *out++ = c++);
                predicate = 0;
            }
        }
        in++;
    }

    *out = 0; // null-terminate buf
    return strdup(buf);
}

void dotest(const char* const input)
{
    char* ex = expand(input);
    printf("input : '%s'\noutput: '%s'\n\n", input, ex);

    if (ex)
        free(ex);
}

int main (int argc, char *argv[])
{
    dotest("a-z or 0-9 or a-b-c or a-z0-9"); // from the original post
    dotest("This is some e-z test in 5-7 steps; this works: a-b-c. This works too: b-k-c-e. Likewise 8-4-6"); // from my C++ answer
    dotest("-x-s a-9 9- a-k-9 9-a-c-7-3"); // assorted torture tests

    return 0;
}

测试输出:

input : 'a-z or 0-9 or a-b-c or a-z0-9'
output: 'abcdefghijklmnopqrstuvwxyz or 0123456789 or abc or abcdefghijklmnopqrstuvwxyz0123456789'

input : 'This is some e-z test in 5-7 steps; this works: a-b-c. This works too: b-k-c-e. Likewise 8-4-6'
output: 'This is some efghijklmnopqrstuvwxyz test in 567 steps; this works: abc. This works too: bcdefghijk. Likewise 45678'

input : '-x-s a-9 9- a-k-9 9-a-c-7-3'
output: '-stuvwx a-9 9- abcdefghijk-9 9-abc-34567'
2020-07-28