有人知道确定字符串值是否“符合”浮点数的便捷方法吗?
bool IsFloat( string MyString )
{
... etc ...
return ... // true if float; false otherwise
}
有人知道确定字符串值是否“符合”浮点数的便捷方法吗?
bool IsFloat( string MyString )
{
... etc ...
return ... // true if float; false otherwise
}
如果你不能使用 Boost 库函数,你可以像这样编写自己的 isFloat 函数。
#include <string>
#include <sstream>
bool isFloat( string myString ) {
std::istringstream iss(myString);
float f;
iss >> noskipws >> f; // noskipws considers leading whitespace invalid
// Check the entire string was consumed and if either failbit or badbit is set
return iss.eof() && !iss.fail();
}
您可能喜欢 Boost 的 lexical_cast(参见http://www.boost.org/doc/libs/1_37_0/libs/conversion/lexical_cast.htm)。
bool isFloat(const std::string &someString)
{
using boost::lexical_cast;
using boost::bad_lexical_cast;
try
{
boost::lexical_cast<float>(someString);
}
catch (bad_lexical_cast &)
{
return false;
}
return true;
}
您可以使用 istream 来避免需要 Boost,但坦率地说,Boost 实在是太好了,不能省略。
受此答案的启发,我修改了函数以检查字符串是否为浮点数。它不需要 boost 并且不依赖于 stringstreams failbit - 它只是简单的解析。
static bool isFloatNumber(const std::string& string){
std::string::const_iterator it = string.begin();
bool decimalPoint = false;
int minSize = 0;
if(string.size()>0 && (string[0] == '-' || string[0] == '+')){
it++;
minSize++;
}
while(it != string.end()){
if(*it == '.'){
if(!decimalPoint) decimalPoint = true;
else break;
}else if(!std::isdigit(*it) && ((*it!='f') || it+1 != string.end() || !decimalPoint)){
break;
}
++it;
}
return string.size()>minSize && it == string.end();
}
IE
1
2.
3.10000
4.2f
-5.3f
+6.2f
被此函数正确识别为浮点数。
1.0.0
2f
2.0f1
是无效浮点数的示例。如果您不想识别 X.XXf 格式的浮点数,只需删除条件:
&& ((*it!='f') || it+1 != string.end() || !decimalPoint)
从第 9 行开始。如果您不想识别没有“。”的数字。作为浮点数(即不是'1',只有'1.','1.0','1.0f'...),那么您可以将最后一行更改为:
return string.size()>minSize && it == string.end() && decimalPoint;
然而:使用 boost 的 lexical_cast 或使用 stringstreams 的解决方案而不是这个“丑陋的函数”有很多很好的理由。但它让我可以更好地控制我想要识别为浮点数的格式(即小数点后的最大位数......)。
我最近写了一个函数来检查一个字符串是否是一个数字。此数字可以是整数或浮点数。
您可以扭曲我的代码并添加一些单元测试。
bool isNumber(string s)
{
std::size_t char_pos(0);
// skip the whilespaces
char_pos = s.find_first_not_of(' ');
if (char_pos == s.size()) return false;
// check the significand
if (s[char_pos] == '+' || s[char_pos] == '-') ++char_pos; // skip the sign if exist
int n_nm, n_pt;
for (n_nm = 0, n_pt = 0; std::isdigit(s[char_pos]) || s[char_pos] == '.'; ++char_pos) {
s[char_pos] == '.' ? ++n_pt : ++n_nm;
}
if (n_pt>1 || n_nm<1) // no more than one point, at least one digit
return false;
// skip the trailing whitespaces
while (s[char_pos] == ' ') {
++ char_pos;
}
return char_pos == s.size(); // must reach the ending 0 of the string
}
void UnitTest() {
double num = std::stod("825FB7FC8CAF4342");
string num_str = std::to_string(num);
// Not number
assert(!isNumber("1a23"));
assert(!isNumber("3.7.1"));
assert(!isNumber("825FB7FC8CAF4342"));
assert(!isNumber(" + 23.24"));
assert(!isNumber(" - 23.24"));
// Is number
assert(isNumber("123"));
assert(isNumber("3.7"));
assert(isNumber("+23.7"));
assert(isNumber(" -423.789"));
assert(isNumber(" -423.789 "));
}
我想你想在输入字符串上运行正则表达式匹配。我认为测试所有边缘情况可能相当复杂。
这个网站有一些很好的信息。如果您只想跳到最后,它会说:
^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$
如果您了解正则表达式语法,这基本上是有道理的。
[编辑:固定以禁止初始空格和尾随废话。]
#include <sstream>
bool isFloat(string s) {
istringstream iss(s);
float dummy;
iss >> noskipws >> dummy;
return iss && iss.eof(); // Result converted to bool
}
您可以轻松地将其转换为基于类型T
而不是float
. 这本质上就是 Boost 的lexical_cast所做的。
使用快速而肮脏的解决方案std::stof
:
bool isFloat(const std::string& s) {
try {
std::stof(s);
return true;
} catch(...) {
return false;
}
}
我一直很喜欢strtof
,因为它可以让你指定一个结束指针。
bool isFloat(const std::string& str)
{
char* ptr;
strtof(str.c_str(), &ptr);
return (*ptr) == '\0';
}
这是有效的,因为结束指针指向解析开始失败的字符,因此如果它指向一个空终止符,那么整个字符串被解析为一个浮点数。
我很惊讶在这个问题出现的 10 年里没有人提到这种方法,我想是因为它更像是一种C 风格的方法。但是,它在 C++ 中仍然完全有效,并且比任何流解决方案都更优雅。此外,它适用于“+inf”“-inf”等,并忽略前导空格。
编辑
不要被空字符串抓住,否则结束指针将在 nul 终止(因此返回 true)。上面的代码应该是:
bool isFloat(const std::string& str)
{
if (str.empty())
return false;
char* ptr;
strtof(str.c_str(), &ptr);
return (*ptr) == '\0';
}
您可以使用如何在 C++ 中将字符串转换为双精度值中描述的方法?, 而不是抛出 a conversion_error
,而是返回false
(表示字符串不代表 a float
),true
否则。
其他响应的主要问题是性能
通常你不需要每个角落的情况,例如也许 nan 和 -/+ inf,并不像速度一样重要。也许您不需要处理 1.0E+03 表示法。您只需要一种将字符串解析为数字的快速方法。
这是一个简单的纯 std::string 方式,速度不是很快:
size_t npos = word.find_first_not_of ( ".+-0123456789" );
if ( npos == std::string::npos ) {
val = atof ( word.c_str() );
}
这很慢,因为它是 O(k*13),检查每个字符与 0 thur 9
这是一种更快的方法:
bool isNum = true;
int st = 0;
while (word.at(st)==32) st++; // leading spaces
ch = word.at(st);
if (ch == 43 || ch==45 ) st++; // check +, -
for (int n = st; n < word.length(); n++) {
char ch = word.at(n);
if ( ch < 48 || ch > 57 || ch != 46 ) {
isNum = false;
break; // not a num, early terminate
}
}
如果发现任何非数字字符,这具有提前终止的好处,并且它通过范围而不是每个数字位(0-9)进行检查。所以平均比较是每个字符 3 次,O(k*3),提前终止。
请注意,此技术与 stdlib 'atof' 函数中使用的实际技术非常相似: http ://www.beedub.com/Sprite093/src/lib/c/stdlib/atof.c
使用 C++17:
bool isNumeric(std::string_view s)
{
double val;
auto [p, ec] = std::from_chars(s.data(), s.data() + s.size(), val);
return ec == std::errc() && p == s.data() + s.size();
}
退货时的两项检查都是必要的。第一个检查没有溢出或其他错误。第二个检查是否读取了整个字符串。
您可以使用atof然后对 进行特殊处理0.0
,但我认为这不是一个特别好的解决方案。
这是关于 SO 的常见问题。查看this question以获取建议(该问题讨论了string->int,但方法相同)。
注意:要知道字符串是否可以转换,您基本上必须进行转换以检查诸如上溢/下溢之类的事情。
您可以做的是使用 istringstream 并根据流操作的结果返回 true/false。像这样的东西(警告 - 我什至没有编译代码,这只是一个指导方针):
float potential_float_value;
std::istringstream could_be_a_float(MyString)
could_be_a_float >> potential_float_value;
return could_be_a_float.fail() ? false : true;
这取决于信任级别、您的需要以及输入数据的来源。如果数据来自用户,则与导入的表数据相比,您必须更加小心,因为您已经知道所有项目都是整数或浮点数,而这只是您需要区分的内容。
例如,最快的版本之一会简单地检查“。”的存在。和其中的“eE”。但是,您可能想看看其余的是否都是数字。在开头跳过空格 - 但不在中间,检查单个“。” “eE”等
因此,q&d 快速破解可能会导致更复杂的 regEx 类(调用它或自己扫描)方法。但是,你怎么知道结果——虽然看起来像一个浮点数——确实可以在你的机器中表示(即尝试 1.2345678901234567890e1234567890)。当然,您可以在尾数/指数中使用“最多 N”位数字制作正则表达式,但有时就是机器/操作系统/编译器或任何特定的。
所以,最后,可以肯定的是,你可能不得不调用底层系统的转换,看看你得到了什么(异常、无穷大或 NAN)。
我很想忽略前导空格,因为这也是该atof
函数的作用:
该函数首先根据需要丢弃尽可能多的空白字符,直到找到第一个非空白字符。然后,从这个字符开始,尽可能多地采用类似于浮点文字的语法的有效字符,并将它们解释为数值。最后一个有效字符之后的字符串的其余部分将被忽略,并且对该函数的行为没有影响。
因此,为了匹配这一点,我们将:
bool isFloat(string s)
{
istringstream iss(s);
float dummy;
iss >> skipws >> dummy;
return (iss && iss.eof() ); // Result converted to bool
}
int isFloat(char *s){
if(*s == '-' || *s == '+'){
if(!isdigit(*++s)) return 0;
}
if(!isdigit(*s)){return 0;}
while(isdigit(*s)) s++;
if(*s == '.'){
if(!isdigit(*++s)) return 0;
}
while(isdigit(*s)) s++;
if(*s == 'e' || *s == 'E'){
s++;
if(*s == '+' || *s == '-'){
s++;
if(!isdigit(*s)) return 0;
}else if(!isdigit(*s)){
return 0;
}
}
while(isdigit(*s)) s++;
if(*s == '\0') return 1;
return 0;
}
我一直在寻找类似的东西,找到了一个比我见过的任何答案都简单得多的答案(虽然适用于浮点数 VS. ints,但仍需要从字符串进行类型转换)
bool is_float(float val){
if(val != floor(val)){
return true;
}
else
return false;
}
或者:
auto lambda_isFloat = [](float val) {return (val != floor(val)); };
希望这可以帮助 !
兹马兹