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

因此,问题在于编写优化的函数,该函数将从输入字符串printf返回第一个pos格式序列n的开头及其长度str

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


怎么做(欢迎聪明又狡猾的方式)?

最佳答案

向前扫描%,然后从那里解析内容。有一些古怪的东西,但还不错(不确定您要使其成为inline吗?)。

一般原则(我只是随便输入内容,因此可能不是有史以来最好的代码形式,而且我也没有尝试过编译)。

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());
     }
 }


edit2:这一点最好写成:

             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”。如果您希望代码拒绝此类事情,那么这并不是很多额外的工作,只需要一点点逻辑来检查“检查特殊字符或数字”中的“我们以前看过此字符”,然后在大多数情况下,特殊字符只能被允许一次。正如评论所言,我可能错过了几个有效的格式说明符。如果您还需要处理“'c'不允许使用'l'”或此类规则,则将变得更加棘手。但是,如果输入的内容不是“恶意的”(​​例如,您要注释有效的C源文件中的哪一行有格式说明符),那么上面的代码应该可以正常工作。

10-07 19:34
查看更多