0

我搜索了最简洁有效的方法来查找 printfC++ 字符串中的第一个格式序列(转换规范)(我不能使用std::regex,因为它们尚未在大多数编译器中实现)。

所以问题是编写一个优化的函数,它将从输入字符串返回第一个printf格式序列的开头pos及其长度:nstr

inline void detect(const std::string& str, int& pos, int& n);

例如,对于:

  • %d -> pos = 0n = 2
  • the answer is: %05d -> pos = 15n = 4
  • the answer is: %% %4.2f haha -> pos = 18n = 5

如何做到这一点(欢迎聪明和棘手的方法)?

4

1 回答 1

0

向前扫描%,然后从那里解析内容。有一些古怪的,但还不错(不确定你想把它变成一个inlinetho')。

一般原则(我只是一边打字,所以可能不是有史以来最好的代码形式——而且我根本没有尝试编译它)。

inline void detect(const std::string& str, int& pos, int& n)
{
    std::string::size_type last_pos = 0;
    for(;;)
    {
         last_pos = str.find('%', last_pos)
         if (last_pos == std::string::npos)
             break;    // Not found anythin. 
         if (last_pos == str.length()-1) 
             break;     // Found stray '%' at the end of the string. 
         char ch = str[last_pos+1];

         if (ch == '%')   // double percent -> escaped %. Go on for next. 
         {
             last_pos += 2;
             continue;
         }
         pos = last_pos; 
         do 
         {
             if (isdigit(ch)) || ch == '.' || ch == '-' || ch == '*' ||
                 ch == '+' || ch == 'l' || ch == 'L' || ch == 'z' || 
                 ch == 'h' || ch == 't' || ch == 'j' || ch == ' ' || 
                 ch == '#' || ch == '\'')
             {
                last_pos++;
                ch = str[last_pos+1]; 
             }
             else
             {
                 // The below string may need appending to depending on version
                 // of printf.  
                 if (string("AacdeEfFgGiopusxX").find(ch) != std::string::npos)
                 {
                     // Do something about invalid string? 
                 }
                 n = last_pos - pos; 
                 return; 
              }
         } while (last_pos < str.length()); 
     }
 }

编辑2:这个位可能最好写成:

             if (isdigit(ch)) || ch == '.' || ch == '-' || ch == '*' ||
                 ch == '+' || ch == 'l' || ch == 'L' || ch == 'z' || 
                 ch == 'h' || ch == 't' || ch == 'j' || ch == ' ' || 
                 ch == '#' || ch == '\'') ... 

 if (string("0123456789.-*+lLzhtj #'").find(ch) != std::string::npos) ... 

现在,这就是你的功课。请报告你的成绩。

编辑:应该注意的是,上面的代码接受了一些常规 printf 将“拒绝”的东西,例如“%.......5......6f”、“%5.8d”、 “%-5-6d”或“%-----09---5555555555555555llllld”。如果你想让代码拒绝这类事情,这并不是一个巨大的额外工作,只需要一点逻辑来检查“检查特殊字符或数字”中的“我们以前见过这个字符吗”,并且在大多数情况下,特殊字符只允许出现一次。正如评论所说,我可能错过了几个有效的格式说明符。如果您还需要处理“这个 'l' 不允许与 'c' 一起使用”或类似规则,它会变得更加棘手。但是如果输入不是“恶意的”(​​例如

于 2013-07-19T23:58:18.087 回答