使用boost检查std::string是否为有效的uuid

8
我想使用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读取的方法,如此处所述。 我想知道是否应该采用这种方法。 任何建议都将不胜感激。


你尝试过正则表达式吗? - Mark Ransom
不用了,我已经在使用boost库并且看到了UUID库,所以想试着使用它。 - ksl
我提到这个是因为 Boost.Regex ,我相信它是 C++11 的 regex 基础。 - Mark Ransom
3个回答

6

您之前的代码在验证方面没有做任何事情,而是基于传递的常量生成UUID(类似哈希函数)。

仔细查看后发现我犯了错误。缺少的验证部分似乎是版本检查:

在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
@ksl 看来我想到的是name_generator。(名字中的“generator”一词让我误解了)。然后,是的,您也可以使用string_generator。要验证UUID,请在解析后检查version():如果它是version_unknown(或任何其他类型),则可以使其失败。 - sehe
@ksl 我已经更新了答案,并提供了一个修复后的演示程序,可以正确识别正确/无效的UUID。 - sehe
1
@sehe 第二个例子('00000000-0000-4000-0000-000000000000')不应该是一个有效的 UUID,因为根据通用格式 xxxxxxxx-xxxx-Vxxx-yxxx-xxxxxxxxxxxx,y 必须是 8、9、a 或 b。来源 - Scis
1
@Scis 在这里每天都在学习... 在这种情况下,正则表达式似乎很适合您的目的。 我想这违反了责任分离原则,所以如果 Boost Uuid 获得域逻辑会更好。 此外,请不要忘记大小写不敏感。 - sehe

5
这似乎更简单:
#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

4

既然您已经使用了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
}

如此答案维基百科中提到,UUID中应该有一个有效的版本号和另一个“特殊”数字。在Coliru上实时查看

1
boost::regex 现在也是 C++11 的 std::regex。 - Sundae
@Scis 我没有说C++11不是一个选项。不确定你为什么这么想。它是一个选项。 - ksl
@ksl 抱歉,我的错。由于某种原因,我以为“不”是关于c11的(有人问了然后删除了评论)。但这并没有改变什么,只是你可以使用#include <regex>std::regex。就像在这个例子中一样。 - Scis

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