繁体   English   中英

在进行url编码时,std :: regex_replace不适用于字符“ +”

[英]While doing url encoding, the std::regex_replace doesn't work properly for character “+”

以下是代码段,regex_replace不适用于字符“ +”,我不应对字符进行特殊处理,但应能正常工作。

/*All headerfiles are available.*/



std::string charToHex(unsigned char c, bool bUpperCase);
std::string urlEncode(const std::string& toEncode, bool bEncodeForwardSlash);
std::string getEncodedUrl(const std::string& url){
std::string bktObjKey = "";

std::string urlEnc = url;

boost::regex expression("^(([^:/?#]+):)?(//([^/?#:]*)(:\\d+)?)?([^?#]*)((\\?[^#]*))?(#(.*))?");

std::string::const_iterator start=url.begin(), end = url.end();
boost::match_results<std::string::const_iterator> what;
boost::match_flag_type flags = boost::match_default;
if (regex_search(url.begin(), url.end(), what, expression, flags)) {
  std::cout<<"Matched"<<std::endl;
  bktObjKey.insert(bktObjKey.begin(), what[6].first, what[6].second);

  std::regex fobj(bktObjKey);
  /*std::string fobj = bktObjKey;*/

  /*auto pos = url.find(bktObjKey);*/
  bktObjKey = urlEncode(bktObjKey, false);
  std::cout<<"bktObjKey :"<<bktObjKey.c_str()<<" urlEnc: "<<urlEnc.c_str()<<std::endl;

  urlEnc = std::regex_replace(url, fobj, bktObjKey);
  std::cout<<" urlEnc: "<<urlEnc.c_str()<<std::endl;
}
  return urlEnc;
}
std::string urlEncode(const std::string& toEncode, bool bEncodeForwardSlash)  {
  std::ostringstream out;

  std::cout<<"inside encode"<<std::endl;
  for(std::string::size_type i=0; i < toEncode.length(); ++i) {
    char ch = toEncode.at(i);
    if ((ch >= 'A' && ch <= 'Z') ||
        (ch >= 'a' && ch <= 'z') ||
        (ch >= '0' && ch <= '9') ||
        (ch == '_' || ch == '-' || ch == '~' || ch == '.') ||
        (ch == '/' && !bEncodeForwardSlash)) {
      out << ch;
      std::cout<<out.str()<<" Is not coded to HEX"<<std::endl;
    }
    else {
      out << "%" <<  charToHex(ch, true);
      std::cout<<out.str()<<" Is coded to HEX"<<std::endl;
    }
  }
  std::cout<<"Return :"<<out.str()<<std::endl;
  return out.str();
}

std::string charToHex(unsigned char c, bool bUpperCase) {
  short i = c;
  std::stringstream s;
  s << std::setw(2) << std::setfill('0') << std::hex << i;
  return s.str();
}

int main() {

std::string url1 ="http://10.130.0.36/rbkt10/+";
std::string out1 = getEncodedUrl(url1);
std::cout<<"Encoded URL1=:"<<out1<<std::endl;

return 0;
}

输出:编码的URL1 =: http : //10.130.0.36/rbkt10/%2b+

因此输出变为“ ++”。 它只能是“ +”。 如何使它完美运行?

  1. 您正在将原始字符串解释为正则表达式。 +在正则表达式¹中是特殊的。

    您应该只使用std::string::replace因为您不需要正则表达式替换功能:

     boost::smatch what; if (regex_search(url.cbegin(), url.cend(), what, expression)) { boost::ssub_match query = what[6]; url.replace(query.first, query.second, urlEncode(query.str(), false)); } 
  2. 复杂的,分散的代码是这样的:
    可能只是:

     std::string bktObjKey = what[6].str(); 
  3. 复杂循环

     for (std::string::size_type i = 0; i < toEncode.length(); ++i) { char ch = toEncode.at(i); 

    可能只是

     for (char ch : toEncode) { 
  4. charToHex每次charToHex创建一个新的2字符字符串,每次都使用另一个stringstream,将结果从stringstream中复制出来,等等。相反,只需写入您拥有的stringstream并避免所有效率低下:

     void writeHex(std::ostream& os, unsigned char c, bool uppercase) { os << std::setfill('0') << std::hex; if (uppercase) os << std::uppercase; os << std::setw(2) << static_cast<int>(c); } 

    请注意,这还可以解决您忘记使用bUppercase

  5. 查看<cctype>以帮助对字符进行分类。

  6. 使用原始文字来编写

     boost::regex expression("^(([^:/?#]+):)?(//([^/?#:]*)(:\\\\d+)?)?([^?#]*)((\\\\?[^#]*))?(#(.*))?"); 

    改为:

     boost::regex expression(R"(^(([^:/?#]+):)?(//([^/?#:]*)(:\\d+)?)?([^?#]*)((\\?[^#]*))?(#(.*))?)"); 

    (无需加倍转义\\d\\?

  7. 要么删除所有冗余子组

     boost::regex expression(R"(^([^:/?#]+:)?(//[^/?#:]*(:\\d+)?)?[^?#]*(\\?[^#]*)?(#.*)?)"); 

    或使其可维护和有用²:

     boost::regex uri_regex( R"(^((?<scheme>[^:/?#]+):)?)" R"((?<authority>//(\\?<host>[^/?#:]*)(:(?<port>\\d+))?)?)" R"((?<path>[^?#]*))" R"((\\?(?<query>([^#]*)))?)" R"((#(?<fragment>.*))?)"); 
  8. 现在,您可以访问URI的逻辑组件,将其应用于更好地了解何时何地进行编码:

      std::string escaped = what["scheme"].str() + what["authority"].str() + urlEncode(what["path"].str(), false); if (query.matched) { escaped += '?'; escaped.append(urlEncode(query, true)); } if (fragment.matched) { escaped += '#'; escaped.append(urlEncode(fragment, true)); } 
  9. 重载采用现有ostream引用的urlEncode ,而不是始终创建自己的引用:

     std::ostringstream out; out << what["scheme"] << what["authority"]; urlEncode(out, what["path"], false); if (query.matched) urlEncode(out << '?', query, true); if (fragment.matched) urlEncode(out << '#', fragment, true); 

审查后的代码

生活在Coliru

#include <boost/regex.hpp>
#include <iostream>
#include <iomanip>

void writeHex(std::ostream& os, unsigned char c, bool uppercase) {
    os << std::setfill('0') << std::hex;
    if (uppercase) 
        os << std::uppercase;
    os << '%' << std::setw(2) << static_cast<int>(c);
}

void urlEncode(std::ostream& os, const std::string &toEncode, bool bEncodeForwardSlash) {
    auto is_safe = [=](uint8_t ch) {
        return std::isalnum(ch) ||
            (ch == '/' && !bEncodeForwardSlash) ||
            std::strchr("_-~.", ch);
    };

    for (char ch : toEncode) {
        if (is_safe(ch))
            os << ch;
        else
            writeHex(os, ch, true);
    }
}

std::string urlEncode(const std::string &toEncode, bool bEncodeForwardSlash) {
    std::ostringstream out;
    urlEncode(out, toEncode, bEncodeForwardSlash);
    return out.str();
}

std::string getEncodedUrl(std::string url) {

    boost::regex uri_regex(
        R"(^((?<scheme>[^:/?#]+):)?)"
        R"((?<authority>//(\?<host>[^/?#:]*)(:(?<port>\d+))?)?)"
        R"((?<path>[^?#]*))"
        R"((\?(?<query>([^#]*)))?)"
        R"((#(?<fragment>.*))?)");

    boost::match_results<std::string::iterator> what;
    //boost::smatch what;
    if (regex_search(url.begin(), url.end(), what, uri_regex)) {
        auto& full     = what[0];
        auto& query    = what["query"];
        auto& fragment = what["fragment"];

        std::ostringstream out;
        out << what["scheme"] << what["authority"];
        urlEncode(out, what["path"], false);

        if (query.matched)
            urlEncode(out << '?', query, true);

        if (fragment.matched)
            urlEncode(out << '#', fragment, true);

        url.replace(full.begin(), full.end(), out.str());
    }
    return url;
}

int main() {
    for (std::string url : { 
            "http://10.130.0.36/rbkt10/+",
            "//10.130.0.36/rbkt10/+",
            "//localhost:443/rbkt10/+",
            "https:/rbkt10/+",
            "https:/rbkt10/+?in_params='please do escape / (forward slash)'&more#also=in/fragment",
            "match inside text http://10.130.0.36/rbkt10/+ is a bit fuzzy",
          }) {
        std::cout << "Encoded URL: " << getEncodedUrl(url) << std::endl;
    }
}

打印

Encoded URL: http//10.130.0.36/rbkt10/%2B
Encoded URL: //10.130.0.36/rbkt10/%2B
Encoded URL: //localhost%3A443/rbkt10/%2B
Encoded URL: https/rbkt10/%2B
Encoded URL: https/rbkt10/%2B?in_params%3D%27please%20do%20escape%20%2F%20%28forward%20slash%29%27%26more#also%3Din%2Ffragment
Encoded URL: match inside text http//10.130.0.36/rbkt10/%2B%20is%20a%20bit%20fuzzy

警告

请注意,代码STILL不符合规范:

在此处输入图片说明

这就是为什么您使用库的原因。


¹(这会使+从输入中保留。它不是“重复的”,只是因为/+表示1或更多/而不被替换)。

²参见https://en.wikipedia.org/wiki/Uniform_Resource_Identifier#Generic_syntax

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM