Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/155.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 解析HTTP';s摘要身份验证?_C++_Regex - Fatal编程技术网

C++ 解析HTTP';s摘要身份验证?

C++ 解析HTTP';s摘要身份验证?,c++,regex,C++,Regex,我有一个程序来解析HTTP摘要的组件,如下所示: #include "stdafx.h" #include <iostream> #include <string> #include <regex> #include <unordered_map> int main() { std::string nsInput = R"(Digest realm = "http-auth@example.org", qop= " aut

我有一个程序来解析HTTP摘要的组件,如下所示:

#include "stdafx.h"
#include <iostream>
#include <string>
#include <regex>
#include <unordered_map>

int main()
{
    std::string nsInput = R"(Digest realm = "http-auth@example.org",
        qop= " auth, auth-int ", algorithm = MD5 ,
        nonce ="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v"    ,
        opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS"
    )";
    //  Spaces are inserted into some places of the input intentionally

    std::smatch mat_opt, mat_val;
    std::unordered_map<std::string, std::string> mapDigest;

    try {
        std::regex rex_opt(R"(\s*([A-Za-z]{3,})\s*=)");
        std::regex rex_val(R"(\s*\"\s*(.{3,})\s*\"|\s*(.{3,})\s*,)");

        auto& str = nsInput;
        while (std::regex_search(nsInput, mat_opt, rex_opt))
        {
            if (mat_opt.size() >= 2) {
                auto& field = mat_opt[1].str();
                std::string& next = mat_opt.suffix().str();

                if (std::regex_search(next, mat_val, rex_val) && mat_val.size() >= 2) {
                    auto& value = mat_val[1].str();
                    mapDigest[field] = value;
                }

                str = mat_opt.suffix().str();
            }
        }

        for (auto& itr : mapDigest) {
            std::cout << itr.first << ":" << itr.second << ".\n";
        }
    }
    catch (std::regex_error& e) {
        std::cout << "regex_search failed" << e.what() << "\n";
    }

    return 0;
}
我想解决的是:

1) 空格仍然出现在“qop”值的末尾

2) “算法”的值无法匹配

也许有人会发现这个模糊的原因,以及如何解决它


首先,您的代码无法编译,因为您试图将非常量左值引用绑定到以下行中的临时对象:

// ...
auto& field = mat_opt[1].str();
// ...
std::string& next = mat_opt.suffix().str();
// ...
auto& value = mat_val[1].str();
// ...
我建议删除引用,改用
auto
std::string
。由于具有良好的性能,它几乎没有性能损失

要删除值末尾的空格,可以在正则表达式模式中使用
{3,}?
而不是
{3,}
{3,}
不带
将贪婪地匹配,因此将匹配后面的所有字符(包括空格)

字符串
MD5
与regex模式中的第二个括号匹配,因此您应该通过
mat_val[2]
而不是
mat_val[1]
访问它。可以按如下方式使用条件表达式:

auto value = mat_val[1].matched ? mat_val[1].str() : mat_val[2].str();

顺便说一句,由于您使用的是原始字符串文字,您不需要在正则表达式模式中的字符
之前额外编写
\

首先,您的代码无法编译,因为您正试图将非常量左值引用绑定到以下行中的临时对象:

// ...
auto& field = mat_opt[1].str();
// ...
std::string& next = mat_opt.suffix().str();
// ...
auto& value = mat_val[1].str();
// ...
我建议删除引用,改用
auto
std::string
。因为,它几乎没有性能损失

要删除值末尾的空格,您可以在正则表达式模式中使用
{3,}?
而不是
{3,}
{3,}
不使用
将进行贪婪匹配,从而匹配后面的所有字符(包括空格)

字符串
MD5
与正则表达式模式中的第二个括号匹配,因此您应该通过
mat_val[2]
而不是
mat_val[1]
来访问它。您可以使用条件表达式,如下所示:

auto value = mat_val[1].matched ? mat_val[1].str() : mat_val[2].str();

顺便说一句,因为您使用的是原始字符串文字,所以您不需要在正则表达式模式中的字符
之前额外编写
\

正如其他人所说,正则表达式可能不是解析HTTP摘要的首选武器

然而,我发现这种模式具有挑战性。比必要的更难的是,引号中有分隔符,应该忽略(在qop部分)。您的其他问题源于贪婪匹配(例如{3,}-部分)

无论如何,这是我15分钟后得到的:

=\s*((?:[^,"]|"\s*([^"]*?)\s?")+?)(?=\s*,|$)

更新:我多跑了一英里,只是为了证明我的观点

#include <iostream>
#include <string>
#include <regex>
#include <unordered_map>

int main()
{
    std::string nsInput = R"(Digest realm = "http-auth@example.org",
        qop= " auth, auth-int ", algorithm = MD5 ,
        nonce ="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v"    ,
        opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS"
    )";
    //  Spaces are inserted into some places of the input intentionally

    std::smatch mat_opt, mat_val;
    std::unordered_map<std::string, std::string> mapDigest;

    try {
        std::regex rex_opt(R"(\s*([A-Za-z]{3,})\s*=)");
        std::regex rex_val("=\\s*((?:[^,\"]|\"\\s*([^\"]*?)\\s?\")+?)(?=\\s*,|$)");

        auto& str = nsInput;
        while (std::regex_search(nsInput, mat_opt, rex_opt))
        {
            if (mat_opt.size() >= 2) {
                auto field = mat_opt[1].str();

                if (std::regex_search(nsInput, mat_val, rex_val)) {
                    auto value = mat_val[2].matched ? mat_val[2].str() : mat_val[1].str();
                    mapDigest[field] = value;
                }

                str = mat_opt.suffix().str();
            }
        }

        for (auto& itr : mapDigest) {
            std::cout << itr.first << ":" << itr.second << ".\n";
        }
    }
    catch (std::regex_error& e) {
        std::cout << "regex_search failed" << e.what() << "\n";
    }

    return 0;
}

正如其他人所说,正则表达式可能不是解析HTTP摘要的首选武器

然而,我发现这种模式具有挑战性。比必要的更难的是,引号中有分隔符,应该忽略(在qop部分)。您的其他问题源于贪婪匹配(例如{3,}-部分)

无论如何,这是我15分钟后得到的:

=\s*((?:[^,"]|"\s*([^"]*?)\s?")+?)(?=\s*,|$)

更新:我多跑了一英里,只是为了证明我的观点

#include <iostream>
#include <string>
#include <regex>
#include <unordered_map>

int main()
{
    std::string nsInput = R"(Digest realm = "http-auth@example.org",
        qop= " auth, auth-int ", algorithm = MD5 ,
        nonce ="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v"    ,
        opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS"
    )";
    //  Spaces are inserted into some places of the input intentionally

    std::smatch mat_opt, mat_val;
    std::unordered_map<std::string, std::string> mapDigest;

    try {
        std::regex rex_opt(R"(\s*([A-Za-z]{3,})\s*=)");
        std::regex rex_val("=\\s*((?:[^,\"]|\"\\s*([^\"]*?)\\s?\")+?)(?=\\s*,|$)");

        auto& str = nsInput;
        while (std::regex_search(nsInput, mat_opt, rex_opt))
        {
            if (mat_opt.size() >= 2) {
                auto field = mat_opt[1].str();

                if (std::regex_search(nsInput, mat_val, rex_val)) {
                    auto value = mat_val[2].matched ? mat_val[2].str() : mat_val[1].str();
                    mapDigest[field] = value;
                }

                str = mat_opt.suffix().str();
            }
        }

        for (auto& itr : mapDigest) {
            std::cout << itr.first << ":" << itr.second << ".\n";
        }
    }
    catch (std::regex_error& e) {
        std::cout << "regex_search failed" << e.what() << "\n";
    }

    return 0;
}


为什么要坚持使用正则表达式?
algorithm=MD5
不是
algorithm=“MD5”
,而是模式匹配
\“
正则表达式不是解析HTTP的方式。@Jonathon,Sam我曾经尝试过sscanf、stringstream和spirit,但发现正则表达式可能更容易完成这项工作。如果您知道哪种方法比正则表达式更简单、更优雅,请告诉我。@Brett如果您再次查看该模式,可以看到由“|”运算符分隔的替换,以查找不带引号的值。根据RFC-7616,算法字段没有被引号包围。为什么您坚持使用正则表达式?
algorithm=MD5
不是
algorithm=“MD5”
,而是模式匹配
\“
正则表达式不是解析HTTP的方式。@Jonathon,Sam我曾经尝试过sscanf、stringstream和spirit,但发现正则表达式可能更容易完成这项工作。如果您知道哪种方法比正则表达式更简单、更优雅,请告诉我。@Brett如果您再次查看该模式,可以看到由“|”运算符分隔的替换,以查找不带引号的值。根据RFC-7616,算法字段没有引号。我忘记了:您要查找的值总是在匹配的最后一组中。所以,通常是第三组,只有MD5才是第二组。谢谢你的回答,不幸的是你的模式不起作用。它起作用了。你点击演示链接了吗?是的,演示看起来很有效,但是只有值匹配,它没有考虑字段的名称。我将你的模式复制到我的源代码中,MSVC给出了错误的输出。是的,它可以工作。我意识到,为了适应您的模式,您已经更改了代码中的一些点,否则输出将不正确。谢谢你的努力。我忘了:你寻找的价值总是在比赛的最后一组。所以,通常是第三组,只有MD5才是第二组。谢谢你的回答,不幸的是你的模式不起作用。它起作用了。你点击演示链接了吗?是的,演示看起来很有效,但是只有值匹配,它没有考虑字段的名称。我将你的模式复制到我的源代码中,MSVC给出了错误的输出。是的,它可以工作。我意识到,为了适应您的模式,您已经更改了代码中的一些点,否则输出将不正确。谢谢你的努力。谢谢你的建议。现在它就像一个符咒。有一件事是,我发布的代码在VS2017之前编译得很好,无论如何,最好删除引用。谢谢你的提示。现在它就像一个符咒。有一件事是,我发布的代码在VS2017之前编译得很好,无论如何,最好删除引用。