【问题标题】:Formatting an integer in C++在 C++ 中格式化整数
【发布时间】:2010-05-12 02:13:26
【问题描述】:

我有一个 8 位整数,我想打印如下格式:

XXX-XX-XXX

我想使用一个接受 int 并返回字符串的函数。

有什么好的方法可以做到这一点?

【问题讨论】:

    标签: c++ string g++


    【解决方案1】:

    这就是我个人的做法。可能不是解决问题的最快方法,而且绝对不像 egrunin 的函数那样可重用,但它让我觉得既干净又易于理解。我会将它作为数学和循环解决方案的替代方案。

    #include <sstream>
    #include <string>
    #include <iomanip>
    
    std::string format(long num) {
      std::ostringstream oss;
      oss << std::setfill('0') << std::setw(8) << num;
      return oss.str().insert(3, "-").insert(6, "-");
    };
    

    【讨论】:

    • 绝对是所有答案中最容易理解(即阅读)的。
    【解决方案2】:

    测试过,它有效。

    这里的format 参数是“XXX-XX-XXX”,但它只查看(并跳过)破折号。

    std::string foo(char *format, long num)
    {
        std::string s(format);
    
        if (num < 0) { return "Input must be positive"; }
    
        for (int nPos = s.length() - 1; nPos >= 0; --nPos)
        {
            if (s.at(nPos) == '-') continue;
    
            s.at(nPos) = '0' + (num % 10);
            num = num / 10;
        }
    
        if (num > 0) { return "Input too large for format string"; }
    
        return s;
    }
    

    用法:

    int main()
    {
        printf(foo("###-##-###", 12345678).c_str());
    
        return 0;
    }
    

    【讨论】:

    • 但是cout &lt;&lt; foo("###-##", 12345) &lt;&lt; endl 是做什么的?如果该函数仅适用于一种特定长度的格式字符串,您应该使用assert。 IMO 你应该assert 范围条件而不是默默地失败。
    • 不仅是 YAGNI,还会复制标准库中已有的内容。几乎足以有资格获得 -1...
    • 为了抽象,我会使用if (s.at(nPos) != '#') continue;而不是if (s.at(nPos) == '-') continue;
    • 大家好,这是一个示例,它解决了确切的问题并提出了进一步解决问题的方法...我的意思是,您不会在其中留下“真正的错误”生产代码,你呢?嘘,强硬的人群。我本人是 YAGNI 的忠实信徒。
    • 是的,这是一个艰难的人群,但你也得到了一些赞成票来接受批评。如果有什么安慰的话,我现在有点自嘲自己在这件事上花费的时间比我不得不愤怒地解决这个问题的时间要长得多。
    【解决方案3】:

    这是尝试使用标准库并让它完成大部分实际工作的一种不同的方式:

    #include <locale>
    
    template <class T>
    struct formatter : std::numpunct<T> {
    protected:
        T do_thousands_sep() const { return T('-'); }
        std::basic_string<T> do_grouping() const {
            return std::basic_string<T>("\3\2\3");
        }
    };
    
    #ifdef TEST
    
    #include <iostream>
    
    int main() {
        std::locale fmt(std::locale::classic(), new formatter<char>);   
        std::cout.imbue(fmt);
    
        std::cout << 12345678 << std::endl;
        return 0;
    }
    
    #endif
    

    要返回一个字符串,只需写入一个字符串流,然后返回它的.str()

    如果您只想以这种方式打印出一个数字,这可能有点矫枉过正,但如果您想在多个地方做这种事情(或者,特别是,如果您想格式化 all em> 数字以这种方式进入特定的流)变得更加合理。

    【讨论】:

    • 我真的看不到太多人以这种方式真正解决这个特定问题,但是 +1 以获得最棒的答案。
    【解决方案4】:

    这是一个完整的程序,展示了我是如何做到的:

    #include <iostream>
    #include <iomanip>
    #include <sstream>
    
    std::string formatInt (unsigned int i) {
        std::stringstream s;
        s << std::setfill('0') << std::setw(3) << ((i % 100000000) / 100000) << '-'
          << std::setfill('0') << std::setw(2) << ((i % 100000) / 1000) << '-'
          << std::setfill('0') << std::setw(3) << (i % 1000);
        return s.str();
    }
    
    int main (int argc, char *argv[]) {
        if (argc > 1)
            std::cout << formatInt (atoi (argv[1])) << std::endl;
        else
            std::cout << "Provide an argument, ya goose!" << std::endl;
        return 0;
    }
    

    使用某些输入运行它会给出:

    Input        Output
    --------     ----------
    12345678     123-45-678
    0            000-00-000
    7012         000-07-012
    10101010     101-01-010
    123456789    234-56-789
    -7           949-67-289
    

    最后两个显示了测试的重要性。如果您想要不同的行为,则需要修改代码。如果调用者不会被打扰(或太愚蠢)而无法遵循规则,我通常会选择静默执行规则,但显然有些人喜欢使用最小惊讶原则并提出例外:-)

    【讨论】:

      【解决方案5】:

      您可以使用 std::ostringstream 类将数字转换为字符串。然后您可以使用数字字符串并使用您想要的任何格式打印它们,如以下代码所示:

      std::ostringstream oss;
      oss << std::setfill('0') << std::setw(8) << number;
      std::string str = oss.str();
      if ( str.length() != 8 ){
          // some form of handling
      }else{
          // print digits formatted as desired
      }
      

      【讨论】:

        【解决方案6】:
        int your_number = 12345678;
        
        std::cout << (your_number/10000000) % 10 << (your_number/1000000) % 10 << (your_number/100000) %10 << "-" << (your_number/10000) %10 << (your_number/1000) %10 << "-" << (your_number/100) %10 << (your_number/10) %10 << (your_number) %10;
        

        http://www.ideone.com/17eRv

        它不是一个函数,而是一个按数字解析 int 数字的通用方法。

        【讨论】:

          【解决方案7】:
          #include <iostream>
          #include <string>
          
          using namespace std;
          
          template<class Int, class Bi>
          void format(Int n, Bi first, Bi last)
          {
              if( first == last ) return;
              while( n != 0 ) {
                  Int t(n % 10);
                  n /= 10;
                  while( *--last != 'X' && last != first);
                  *last = t + '0';
              }
          }
          
          int main(int argc, char* argv[])
          {
              int i = 23462345;
              string s("XXX-XX-XXX");
              format(i, s.begin(), s.end());
              cout << s << endl;
              return 0;
          }
          

          【讨论】:

          • 此算法适用于任何整数,只要格式字符串的 X 字符数等于整数的长度。例如,对于 8 位整数,格式字符串必须包含 8 个 X 字符。
          • 因此基于first == last 而不是n == 0 终止可能会更好。
          【解决方案8】:

          怎么样?

          std::string format(int x)
          {
              std::stringstream ss
          
              ss.fill('0');
              ss.width(3);
              ss << (x / 10000);
          
              ss.width(1);
              ss << "-";
          
              ss.width(2);
              ss << (x / 1000) % 100;
          
              ss.width(1);
              ss << "-";
          
              ss.width(3);
              ss << x % 1000;
          
              return ss.str();
          }

          编辑 1:我看到 strstream 已被弃用并替换为 stringstream。

          编辑 2:修复了缺少前导 0 的问题。我知道,这很丑。

          【讨论】:

            【解决方案9】:

            显然是char * 而不是string,但你明白了。完成后您需要释放输出,并且您可能应该添加错误检查,但应该这样做:

            char * formatter(int i)
            {    
              char *buf = malloc(11*sizeof(char));
              sprintf(buf, "%03d-%02d-%03d", i/100000, (i/1000)%100, i%1000);
              return buf;
            }
            

            【讨论】:

            • 为什么是malloc,我们这里是C++
            • 为什么要手动分配?如果有的话,使缓冲区自动而不是动态(sizeof(char) 始终为 1,将缓冲区设置为 16 只是因为它是一个不错的数字),sprintf 放入其中,然后返回 std::string
            【解决方案10】:

            您不需要mallocnew,只需将buf 定义为char buff[11];

            【讨论】:

              猜你喜欢
              • 2021-04-24
              • 1970-01-01
              • 2022-10-30
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2022-01-13
              • 1970-01-01
              • 2011-09-19
              相关资源
              最近更新 更多