我是一个库的开发人员,我们的旧代码使用sscanf()和sprintf()从/到字符串读/写各种内部类型.我们遇到过使用我们库的用户的问题,并且其语言环境与我们基于XML文件的语言环境不同("C"语言环境).在我们的例子中,这导致从这些XML文件解析的值不正确,以及在运行时以字符串形式提交的值.区域设置可以由用户直接更改,但也可以在用户不知情的情况下进行更改.如果区域设置更改发生在另一个库中,例如GTK,这是一个错误报告中的"犯罪者",就会发生这种情况.因此,我们显然希望从语言环境中删除任何依赖关系,以永久地摆脱这些问题.
我已经在float/double/int /的上下文中阅读了其他问题和答案,特别是如果它们被一个字符分隔或位于括号内,但到目前为止,我发现的建议解决方案并不令我们满意.我们的要求是:
除了标准库之外,不依赖于库.因此,使用boost中的任何内容都不是一种选择.
必须是线程安全的.这具体涉及可以全局更改的区域设置.这对我们来说真的很糟糕,因为我们库的一个线程可能会受到用户程序中另一个线程的影响,该线程也可能正在运行一个完全不同的库的代码.setlocale()因此,任何直接受影响的东西都不是一种选择.此外,由于线程中的竞争条件,在开始读/写之前设置区域设置并将其设置回原始值不是解决方案.
虽然效率不是最重要的优先级(#1和#2),但它仍然是我们关注的问题,因为字符串可能会在运行时频繁地读取和写入,具体取决于用户的程序.越快越好.
编辑:作为补充说明:boost::lexical_cast不保证不受语言环境的影响(来源:boost :: lexical_cast <>的语言环境不变保证).即使没有要求#1,这也不是解决方案.
到目前为止,我收集了以下信息:
std::to_string,std::stod,std::stof,等取决于全球区域只是sscanf的方式和sprintf做的,这是非常不幸的,我不理解的,考虑到的std ::螺纹已被添加.std::stringstream似乎是一般的解决方案,因为它在语言环境的上下文中是线程安全的,但一般来说如果保护正确的话.但是,如果它每次都是新建的,那么它很慢(良好的比较:http://www.boost.org/doc/libs/1_55_0/doc/html/boost_lexical_cast/performance.html).我假设这可以通过配置和使用每个线程一个这样的流来解决,每次使用后清除它.但是,问题在于它不能像以下那样容易地解决格式sscanf(),例如:" { %g , %g } ".sscanf() 例如,我们需要能够阅读的模式是:
" { %g , %g }"" { { %g , %g } , { %g , %g } }"" { top: { %g , %g } , left: { %g , %g } , bottom: { %g , %g } , right: { %g , %g }"用stringstreams写这些似乎没什么大不了的,但阅读它们似乎有问题,特别是考虑到空白.
我们应该std::regex在这种情况下使用还是这种矫枉过正?stringstreams是否是这项任务的一个很好的解决方案,或者根据上述要求,还有更好的方法吗?另外,在我的问题中我没有考虑过的线程安全和语言环境中是否有任何其他问题 - 特别是关于std :: stringstream的用法?
在您的情况下,stringstream似乎是最好的方法,因为您可以独立于设置的全局区域设置来控制它的区域设置.但是格式化的阅读确实不是那么容易sscanf().
从性能的角度来看,使用正则表达式进行流输入对于这种简单的逗号分隔读取来说是过度的:在非正式基准测试中,它比scanf()慢10倍以上.
您可以轻松编写一个辅助类,以方便阅读您所枚举的格式.这里关于另一个SO答案的一般想法 使用可以像下面这样简单:
sst >> mandatory_input(" { ")>> x >> mandatory_input(" , ")>>y>> mandatory_input(" } ");
如果你有兴趣,我前段时间写过一篇.这里有完整的文章,包含示例和解释以及源代码.该类是70行代码,但大多数代码在需要时提供错误处理功能.它具有可接受的性能,但仍然比scanf()慢.