【问题标题】:Check if std::string is a valid uuid using boost使用 boost 检查 std::string 是否是有效的 uuid
【发布时间】:2015-04-25 02:17:57
【问题描述】:

我想使用 boost 检查给定的字符串是否是有效的 UUID。

这是我通过查看 boost 网站上的文档得出的结论:

void validate_uuid(const std::string& value)
{
    try
    {
        boost::uuids::string_generator stringGenerator;
        (void)stringGenerator(value);
    }

    catch (const std::exception& ex)
    {
        // ...
    }
}

但是,这并不总是有效。

如果我使用对于有效 UUID 来说太短的字符串调用函数,则会按预期抛出异常。但是,如果我使用无效的 UUID(例如 00000000-0000-0000-0000-00000000000K)调用该函数,则不会引发异常。

请有人解释一下为什么会这样。

另外,我已经看到使用 boost::lexical_cast 将字符串读取为 UUID,正如 here 所发布的那样。我想知道我是否应该遵循这种方法。任何建议表示赞赏。

【问题讨论】:

  • 你试过正则表达式吗?
  • 没有。我已经使用 boost 并且看到了 UUID 库,所以我想我会尝试使用它。
  • 我之所以提到它是因为Boost.Regex 我相信这是C++11's regex 的基础

标签: c++ boost uuid boost-uuid


【解决方案1】:

您的代码在验证方面没有任何作用。相反,它会根据传递的常量生成一个 UUID(如哈希函数)。

仔细一看,我错了。缺少的验证似乎是对版本的检查:

Live On Coliru

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/string_generator.hpp>
#include <iostream>

bool is_valid_uuid(std::string const& maybe_uuid, boost::uuids::uuid& result) {
    using namespace boost::uuids;

    try {
        result = string_generator()(maybe_uuid); 
        return result.version() != uuid::version_unknown;
    } catch(...) {
        return false;
    }
}

int main() {
    std::string maybe_uuid;
    std::cout << "Enter a UUID: ";

    while (std::cin >> maybe_uuid)
    {
        boost::uuids::uuid result;
        bool is_valid = is_valid_uuid(maybe_uuid, result);
        std::cout << "\n'" << maybe_uuid << "' valid: " << std::boolalpha << is_valid << "\n";

        if (is_valid)
            std::cout << "Parsed value: " << result << "\n";
    }
}

Coliru: echo 00000000-0000-{0,4}000-0000-000000000000 $(uuidgen) "{$(uuidgen)}" | ./a.out 的示例输出:

Enter a UUID: 
'00000000-0000-0000-0000-000000000000' valid: false

'00000000-0000-4000-0000-000000000000' valid: true
Parsed value: 00000000-0000-4000-0000-000000000000

'a2c59f5c-6c9b-4800-afb8-282fc5e743cc' valid: true
Parsed value: a2c59f5c-6c9b-4800-afb8-282fc5e743cc

'{82a31d37-6fe4-4b80-b608-c63ec5ecd578}' valid: true
Parsed value: 82a31d37-6fe4-4b80-b608-c63ec5ecd578

【讨论】:

  • 感谢@sehe 的回复。如果传递的字符串不是 UUID 的有效表示,如我的示例所示,它如何生成 UUID?
  • @ksl 好像我在想name_generator。 (正是名称中的“生成器”部分让我走错了路)。那么,是的,你也可以使用string_generator。要验证 UUID,check the version() after parsing:如果是 version_unknown(或您不想允许的任何其他类型),您可以使其失败。
  • @ksl 我已经用一个固定的演示程序更新了答案,该程序可以正确识别正确/无效的 UUID
  • @sehe 第二个示例('00000000-0000-4000-0000-000000000000')不应该是有效的 UUID,因为考虑到一般格式 xxxxxxxx-xxxx-Vxxx-yxxx-xxxxxxxxxxxx y - 必须是 8、9、a 或 b。 source
  • @Scis 每天在这里学习...在这种情况下,正则表达式似乎很符合您的目的。我在想这违反了职责分离,所以如果 Boost Uuid 获得域逻辑会更好。另外,不要忘记不区分大小写
【解决方案2】:

这似乎更容易:

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <iostream>
#include <sstream>

int main()
{
    std::string t1("01234567-89ab-cdef-0123-456789abcdef");
    std::string t2("Test UUID");

    boost::uuids::uuid u;
    std::istringstream iss(t1);
    iss >> u;
    if (iss.good())
        std::cerr << "'" << t1 << "' is a good UUID\n";
    else
        std::cerr << "'" << t1 << "' is not a good UUID\n";

    iss.str(t2);
    iss >> u;
    if (iss.good())
        std::cerr << "'" << t2 << "' is a good UUID\n";
    else
        std::cerr << "'" << t2 << "' is not a good UUID\n";

    return 0;
}

$ g++ -I/usr/local/include -std=c++11 test1.cpp
$ a.out
'01234567-89ab-cdef-0123-456789abcdef' is a good UUID
'Test UUID' is not a good UUID

【讨论】:

    【解决方案3】:

    既然你已经使用了 boost,你可以使用正则表达式来检查你的字符串是否是一个有效的 UUID

    例如,对于 UUID 版本 4,您可以使用以下代码

    bool validate_uuid(const std::string& s)
    {
       static const boost::regex e("[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}");
       return regex_match(s, e); // note: case sensitive now
    }
    

    (正如answerwiki 中提到的,应该有一个有效的版本数字和另一个“特殊”数字)。

    Live on coliru.

    【讨论】:

    • boost::regex 现在也是 C++11 中的 std::regex
    • @Scis 我没有说 C++11 不是一个选项。不知道你为什么这么认为。这是一种选择。
    • @ksl 对不起,我很抱歉,出于某种原因,我认为“否”是关于 c11 的(有人问它,然后删除了评论)。但这并没有太大变化,只是您可以#include &lt;regex&gt; 并改用std::regex。就像在this 示例中一样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-08
    • 2020-06-11
    • 2014-05-08
    • 1970-01-01
    • 2017-08-18
    相关资源
    最近更新 更多