C# String.Format with Parameters 标准等效于 C++

C# String.Format with Parameters standard equivalent in C++?

本文关键字:C++ 标准 Parameters String Format with      更新时间:2023-10-16

我有很多C#代码必须用C++编写。我在C++方面没有太多经验。

我正在使用Visual Studio 2012进行构建。该项目是 C++ 中的静态库(不是 C++/CLI 中的静态库)。

在许多地方,他们使用String.Format,像这样:

C#

String.Format("Some Text {0}, some other Text {1}", parameter0, parameter1);

现在,我知道以前有人问过类似的事情,但我不清楚什么是最标准/最安全的方法。

使用sprintfprintf这样的东西安全吗?我读到有些人提到他们不标准。像这样的东西?(这是C++方式,还是更多的是C方式?

C++(还是C?

char buffer [50];
int n, a=5, b=3;
n=sprintf (buffer, "Some Text %d, some other Text %d", a, b);

其他人建议做自己的类,我看到了许多不同的实现。

目前,我有一个使用std::to_string,ostringstream,std::string.placestd::string.find的类,以及模板。我的类相当有限,但对于我在 C# 代码中遇到的情况,它可以工作。现在我不知道这是最有效的方法(甚至根本不是正确的):

C++

template <typename T>
static std::string ToString(T Number)
{
    std::ostringstream stringStream;
    stringStream << Number;
    std::string string = stringStream.str();
    return string;
};
template <typename T,unsigned S> 
static std::string Format(const std::string& stringValue, const T (&parameters)[S])
{ 
    std::string stringToReturn = std::string(stringValue);
    for (int i = 0; i < S; ++i)
    {
        std::string toReplace = "{"+ std::to_string(i) +"}";
        size_t f = stringToReturn.find(toReplace);
        if(std::string::npos != f)
            stringToReturn.replace(f, toReplace.length(), ToString(parameters[i]));
    }
    return stringToReturn;      
};
//I have some other overloads that call the Format function that receives an array.
template <typename T>
    static std::string Format(const std::string& stringValue, const T parameter, const T parameter2)
    {
        T parameters[] = {parameter, parameter2};
        return Format(stringValue, parameters);
    };

我需要我的代码在 LinuxWindows 中工作,所以我需要不同的编译器才能构建它,这就是为什么我需要确保我使用的是标准方式。而且我的环境不能那么容易更新,所以我不能使用 C++11。我也不能使用 Boost,因为我不确定我是否能够在我需要它工作的不同环境中添加库。

在这种情况下,我可以采取的最佳方法是什么?

这是我为此目的

编写的 1 标头库: 假格式

测试:

REQUIRE(ff::format("{2}ff{1}").with('a').also_with(7).now()=="7ffa");

该库是可配置的,因此您可以从 0 开始参数索引。您还可以编写包装器,使其看起来与String.Format完全相同。

它建立在 Linux 之上,不需要 c++11。

目前还没有标准方法...

或者,您可以使用 Boost.Locale 格式

这是,索引从 0 开始:

#include ...
struct dotnet_config {
  static const char scope_begin='{';
  static const char scope_end='}';
  static const char separator=',';
  static const char equals='=';
  static const size_t index_begin=0;
  static bool string_to_key(std::string const& to_parse,int& res) {
    std::istringstream ss(to_parse);
    ss.imbue(std::locale::classic());
    ss >> res;
    if (!ss.fail() && ss.eof())
      return true;
    return false;
  }
};
template <typename T1>
std::string Format (std::string const& format_string,T1 p1) {
 return ff::formatter<dotnet_config>(format_string).with(p1).now();
}
template <typename T1,typename T2>
std::string Format (std::string const& format_string,T1 p1,T2 p2) {
 return ff::formatter<dotnet_config>(format_string).with(p1).with(p2).now();
}
int main() {
  std::cout<<Format("test={0}",42)<<std::endl;
  std::cout<<Format("{0}!={1}",33,42)<<std::endl;
  return 0;
}

输出:

test=42
33!=42

如果您拥有的只是非对象类型(或者您手动将它们转换为 C 字符串,或将它们转换为字符串,然后调用 c_str() 成员函数),则 sprintf 有效。您可能需要 snprintf 提供的额外保护,防止缓冲区溢出。

如果您愿意学习更多内容来执行您必须做的事情,则可以使用增强格式库。我相信你可以编写一个脚本来将String.format调用转换为Boost的语法。

如果你不能使用Boost,也不能使用C++11,你必须使用sprintf并小心缓冲区溢出(如果你可以依赖你的编译器,可能是snprintf)。您可能希望编写一个脚本来包装所有参数,以便它们都转换为字符串:

String.Format("Some Text {0}, some other Text {1}", to_printf(p0), to_printf(p1));

另外,请注意,C 的格式不使用大括号。所以这是一个大问题。您可能需要实现自己的可变参数函数。


如果一切都像{0}这样简单,你可以编写一个脚本来替换大多数 String.Format 实例(而不是更复杂的实例)

如下
`mystring = "Some Text "+tostring(p0)+", some other Text "+tostring(p1);`

这不是最有效的方法,但除非您每秒执行数千种格式,否则很可能无关紧要。或者可能效率稍高(没有中间字符串):

`"mystring = static_cast<std::ostringstream&>(std::ostringstream().flush()<<Some Text "<<p0<<", some other Text "<<p1).str();`,

这创造了一个临时的。同花顺有点诱使编译器认为它不是临时的,这解决了关于无法使用非成员operator<<的特定问题。

为什么不使用 << 运算符来格式化字符串?

string strOutput;
stringstream strn;
int i = 10;
float f = 20.0f;
strn << "Sally scored "<<i<< " out of "<<f << ". She failed the test!";
strn >> strOutput;
cout << strOutput;