将az扩展为abc … xyzforms的方法

嗨:)我想要做的是写一个简单的程序,从最短的条目扩展

例如

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

写得最久

例如

abc … xyz或0123456789或abc或abcdefghijklmnouprstwxyz0123456789

1-st考试最短录入= 1-example示例结果应该给:)

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

expand(char s[]) { int i,n,c; n=c=0; int len = strlen(s); for(i = 1;s[i] > '0' && 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

谢谢你提前:)

这是一个C版本( 大约38个有效行 ),它满足与我之前的C ++版本相同的测试。

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

合理

我很确定我夸大了要求,但是

  • 这应该是如何以健壮的方式进行解析的一个很好的例子
    • 以明确的方式使用状态
    • validation输入(!)
      • 这个版本不假设acb不可能发生
      • 它也不会像’Hello World’(或(char*) 0 )这样的简单输入阻塞甚至失败
  • 它显示了如何在不使用无关函数的情况下避免printf("%c", c)每个char。
  • 我提出了一些评论来解释为什么会发生什么,但总的来说,你会发现代码更加清晰,无论如何,

    • 远离太多短命名变量
    • 使用不透明的索引器避免复杂的条件
    • 避免整个字符串长度业务:我们只需要2个字符的最大predicate(*it)如果它是空字符, *it=='-'predicate(*it)将返回false快捷方式评估阻止我们访问过去的输入字符
  • 一个警告:我没有对输出缓冲区溢出进行适当的检查(容量在2048个字符处硬编码)。 我将把它作为读者的谚语

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

  • 它允许我比较C ++版本和这个C版本的原始性能,因为它们执行相同的function。 现在,我完全期望C版本的性能优于C ++(让我们猜测:4倍?)但是,让我们再看看GNU编译器为我们带来了多少惊喜。 更多以后 更新结果我不远: github(代码+结果)

纯C实现

不用多说,实现,包括测试用例:

 #include  #include  #include  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("az or 0-9 or abc or a-z0-9"); // from the original post dotest("This is some ez test in 5-7 steps; this works: abc. This works too: bkce. Likewise 8-4-6"); // from my C++ answer dotest("-xs a-9 9- ak-9 9-ac-7-3"); // assorted torture tests return 0; } 

测试输出:

 input : 'az or 0-9 or abc or a-z0-9' output: 'abcdefghijklmnopqrstuvwxyz or 0123456789 or abc or abcdefghijklmnopqrstuvwxyz0123456789' input : 'This is some ez test in 5-7 steps; this works: abc. This works too: bkce. Likewise 8-4-6' output: 'This is some efghijklmnopqrstuvwxyz test in 567 steps; this works: abc. This works too: bcdefghijk. Likewise 45678' input : '-xs a-9 9- ak-9 9-ac-7-3' output: '-stuvwx a-9 9- abcdefghijk-9 9-abc-34567' 

好的,我测试了你的程序,它几乎适用于所有情况。 它只用两个字母/数字正确扩展了az和其他扩展。 当有更多的字母和数字时,它会失败。 修复很简单,只需创建一个新的字符来保留最后打印的字符,如果当前打印的字符与最后一个字符匹配则跳过它。 a-z0-9场景不起作用,因为你忘记了[i]> =’0’而不是s [i]>’0’。 代码是:

 #include  #include  void expand(char s[]) { int i,g,n,c,l; 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]; //printf("\nc = %cg = %cn = %c\n", c,g,n); if(s[0] == '-') printf("%c",s[0]); else if(g == '-') { if(c 

这是K&R的问题吗? 我想我在那里看到了它。 无论如何,我希望我帮助。

基于现有函数分别处理“az”和“0-9”序列的事实,我们应该探讨它们相遇时会发生什么。 跟踪你的代码(尝试在每一步打印每个变量的值 – 是的它会混乱,所以使用换行符),我相信你会在迭代时发现逻辑短路,例如,从“当前令牌是’y ‘和下一个标记是’z’“到”当前标记是’z’而下一个标记是’0’“。 探索if()条件,你会发现它并没有涵盖所有可能性,即如果你在< - > z之内,在0 < - > 9之内,或者完全等于’ – ‘,你已经覆盖了自己,但是你没有考虑在下一个字符的下一个字符的末尾(az或0-9)。

只是为了好玩,我决定向自己certificateC ++真的适合这种事情。

请先测试一下

首先,让我更严格地定义要求:我认为它需要处理这些情况:

 int main() { const std::string in("This is some ez test in 5-7 steps; this works: abc. This works too: bkce. Likewise 8-4-6"); std::cout << "input : " << in << std::endl; std::cout << "output: " << expand(in) << std::endl; } 

input :这是5-7步中的一些ez测试; 这有效: abc 。 这也有效: bkce 。 同样8-4-6
output:这是567步中的一些efghijklmnopqrstuvwxyz测试; 这有效: abc 。 这也有效: bcdefghijk 。 同样45678

C ++ 0x实现

这是C ++ 0x代码1的 14行(23包括空格,注释)中的实现(实际上是一些变体)

 static std::string expand(const std::string& in) { static const regex re(R"([az](?:-[az])+|[0-9](?:-[0-9])+)"); std::string out; auto tail = in.begin(); for (auto match : make_iterator_range(sregex_iterator(in.begin(), in.end(), re), sregex_iterator())) { out.append(tail, match[0].first); // char range bounds: the cost of accepting unordered ranges... char a=127, b=0; for (auto x=match[0].first; x 

当然我作弊有点因为我正在使用Boost的正则表达式迭代器 。 我会做一些时间比较C版本的性能。 我更期待C ++版本在50%的范围内竞争。 但是,让我们看看GNU编译器为我们存储了什么样的惊喜:)

这是一个完整的程序,演示了示例输入。 _它还包含一些基准时间和一些权衡的变化

  • function灵活
  • 易读性/表现

 #include  // only needed for the 'slow variant' #include  #include  using namespace boost; using namespace boost::range; static std::string expand(const std::string& in) { // static const regex re(R"([az]-[az]|[0-9]-[0-9])"); // "acd" --> "abc-d", "aceg" --> "abc-efg" static const regex re(R"([az](?:-[az])+|[0-9](?:-[0-9])+)"); std::string out; out.reserve(in.size() + 12); // heuristic auto tail = in.begin(); for (auto match : make_iterator_range(sregex_iterator(in.begin(), in.end(), re), sregex_iterator())) { out.append(tail, match[0].first); // char range bounds: the cost of accepting unordered ranges... #if !SIMPLE_BUT_SLOWER // debug 15.149s / release 8.258s (at 1024k iterations) char a=127, b=0; for (auto x=match[0].first; x bounds(match[0].first, match[0].second); bounds.erase('-'); for (char c=*bounds.begin(); c<=*bounds.rbegin(); out.push_back(c++)); #endif tail = match.suffix().first; } out.append(tail, in.end()); return out; } int main() { const std::string in("This is some ez test in 5-7 steps; this works: abc. This works too: bkce. Likewise 8-4-6"); std::cout << "input : " << in << std::endl; std::cout << "output: " << expand(in) << std::endl; } 

1g++-4.6 -std=c++0x编译g++-4.6 -std=c++0x