从std::string转换为bool

65

什么是将std :: string转换为bool的最佳方法?我正在调用一个返回“0”或“1”的函数,我需要一个简洁的解决方案将其转换为布尔值。

14个回答

121

我很惊讶没有人提到这个:

bool b;
istringstream("1") >> b;
或者
bool b;
istringstream("true") >> std::boolalpha >> b;

4
声望并不总是与最佳(依我之见)答案相匹配。 :) - gsamaras
不错!使用Lua C API,这对我起作用了。我猜C语言没有布尔数据类型;lua_toboolean()返回一个0或1的整数值,所以在C++中似乎可以解决这个问题。 - Artorias2718
是的,它是C++流 https://www.cprogramming.com/tutorial/c++-iostreams.html。 - David L.

52
bool to_bool(std::string const& s) {
     return s != "0";
}

36

对于你来说可能有些过头了,但我建议使用boost::lexical_cast

boost::lexical_cast<bool>("1") // returns true
boost::lexical_cast<bool>("0") // returns false

由于这个解决方案会带来一些开销,因此在性能重要的情况下不应使用它。或者为自己的需求专门定制boost::lexical_cast。 - smerlin
2
这个比其他任何东西都更健壮吗?它的行为不明确,例如,随机的非零数字会变成true,"true"和空字符串应该抛出异常。(没想好。) - Potatoswatter
@Potatoswatter:编写一个测试程序并查看。在Boost 1.38(我测试的版本)中,0、00等=> false;1、01等=> true;我测试过的其他任何内容(“”,2、3、true、false)都会抛出boost::bad_lexical_cast异常。 - C. K. Young
@smerlin 通常情况下,易读的代码比优化单行代码更受欢迎,就像这个简单的例子一样。Boost解决方案在其意图上很清晰,而纯C++解决方案可能会让某些人感到困惑一段时间。同时,假设Boost使用低效的解决方案是不合理的,因为没有证据支持这种说法。 - user904963
@user904963 这就是为什么我在十一年前写下了“当性能至关重要”的原因。 - smerlin
显示剩余3条评论

17

你要么在意可能出现的无效返回值,要么不在意。到目前为止,大多数答案都处于中间地带,捕获一些字符串而不是“0”和“1”,或许会谈论如何进行转换,或许会抛出异常。无效的输入不能产生有效的输出,你不应该试图接受它。

如果你不在意无效的返回值,请使用s[0] == '1'。这非常简单明了。如果你必须向某人证明其容错能力,请说它将无效的输入转换为false,并且空字符串很可能是你STL实现中的单个\0,因此相对稳定。s == "1"也可以,但s != "0"对我来说似乎很迂腐,并且会使无效输入=> true。

如果你关心错误(并且可能应该),请使用

if ( s.size() != 1
 || s[0] < '0' || s[0] > '1' ) throw input_exception();
b = ( s[0] == '1' );

这可以捕获所有错误,对于懂一点 C 的人来说非常明显和简单,而且没有任何其他方法能够更快。


16

在C++11中也有std::stoi函数:

bool value = std::stoi(someString.c_str());


6

DavidL的回答是最好的,但我发现自己想要同时支持两种形式的布尔输入。所以在这个主题上进行了一些微小变化(以std::stoi命名):

bool stob(std::string s, bool throw_on_error = true)
{
    auto result = false;    // failure to assert is false

    std::istringstream is(s);
    // first try simple integer conversion
    is >> result;

    if (is.fail())
    {
        // simple integer failed; try boolean
        is.clear();
        is >> std::boolalpha >> result;
    }

    if (is.fail() && throw_on_error)
    {
        throw std::invalid_argument(s.append(" is not convertable to bool"));
    }

    return result;
}

这支持 "0"、"1"、"true" 和 "false" 作为有效的输入。不幸的是,我无法找到一种可移植的方法来支持 "TRUE" 和 "FALSE"。


1
为什么不在尝试解析之前将字符串转换为小写?这样你就可以支持 true、TRUE、True 等。 - fuzzy
@fuzzy,关键点在于可移植性。这也适用于不同的语言/区域设置(这是我缺乏经验/技能的领域)。当然可以对字符串进行不区分大小写的比较,但正如您所注意到的,此答案没有字符串文字。它依赖于std::boolalpha流提取器(其又依赖于您的区域设置)。如果将字符串转换为小写适用于您,那太好了。 - jwm
1
可移植性和本地化是两个不同的概念,而你只问了关于可移植性的问题。此外,如果 std::boolalpha 提取器遵循你的语言环境,那么将字符串转换为小写就可以在任何地方使用。std::string lower = s; std::transform( lower.begin(), lower.end(), lower.begin(), ::tolower ); std::istringstream is( lower ); ... <继续使用之前的逻辑> - fuzzy
如果您能够权威地涵盖所有可能的区域设置,那么您比我更明智。然而,经过简短的搜索,我发现了一个混合大小写(可能)的区域设置的示例(链接在此:https://raymii.org/s/articles/Print_booleans_as_True_or_False_in_C++.html)。因此,我不愿意走得那么极端。 - jwm
1
你的例子只显示了一个混合大小写的值,因为作者正在解释如何将由std::boolalpha返回的值更改为任意字符串。 - fuzzy
@jwm,你链接的那篇文章是由一位不熟练的程序员撰写的。他实际上写了true ? "true" : "false"。然后,他实际上说三元运算符很令人困惑......是啊,就像15年前你刚刚了解while循环时第一次看到它一样。此外,他的语境好像是在大型代码库中的企业代码(“想象一下阅读无聊、重复的日志文件,一个0在一堆1中有多容易被忽略”),但他却建议使用printf而不是成熟的日志记录解决方案。 - user904963

5
我建议使用这个,它可以实现你想要的功能,并且可以捕获错误情况。
bool to_bool(const std::string& x) {
  assert(x == "0" || x == "1");
  return x == "1";
}

1
编写一个自由函数:
bool ToBool( const std::string & s ) {
   return s.at(0) == '1';
}

这是可能起作用的最简单的事情,但您需要问自己:

  • 一个空字符串应返回什么?上面的版本会抛出异常
  • 除了 '1' 或 '0' 之外的字符应该转换为什么?
  • 超过一个字符的字符串是否是函数的有效输入?

我相信还有其他问题 - 这就是 API 设计的乐趣所在!


这是我认为最好的方法。使用 at 作为检查非常干净。 - GManNickG
5
@GMan: 我不确定我同意那种说法。在C语言中,0表示假,其他一切都为真。因此,2是真,03也是真,等等。因此,即使问题描述不够明确,假设除了0以外的一切都是真,也是合理的。 - C. K. Young
2
那是假的,但这就是为什么Kornel的解决方案是赢家。:-P - C. K. Young
1
规范中一个明确且毫不含糊的部分是输入只能是“0”或“1”,没有其他。因此,检查“00”、“2”、“03”等内容都属于YAGNI领域。但是,使用at()也是如此。 - Jerry Coffin
2
应该写成!= '0',因为在整数中,除了0以外的任何值都是true。 - user216441
显示剩余2条评论

1
我会修改那个最初返回这个字符串的丑陋函数。这就是布尔型变量存在的意义。

我无法控制这个函数,它是第三方库。 - cquillen
这个库似乎有点愚蠢。它为什么要在布尔返回值上使用std::string呢? - UncleBens
@UncleBens - 也许它使用std::string作为“变体”类型。 - Kornel Kisielewicz

0
这是一种与Kyle相似的方法,不同之处在于它处理前导零和其他东西:
bool to_bool(std::string const& s) {
     return atoi(s.c_str());
}

4
但是但是但是... "DEADBEEF"将被视为假!:-P - C. K. Young
@Andreas:C语言的传统是0为假,其他所有值都为真。理想情况下,我希望在这种情况下抛出异常,但如果这不是一个选项,那么在我看来,true比false“更正确”。 - C. K. Young

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接