ZachSal
ZachSal

Reputation: 131

How to terminate loop at end of string?

I am trying to take all options from this URL (oq, aqs, etc). I'm using a function to extract each one individually. However, I cannot figure out how to terminate the loop once it has reached the final option. I think I am setting res to the current position, but I am not sure. I tried terminating it when !(res == url.length()) but that did not work. Can anyone help with this?

Also, I would appreciate advice on how to scale this to multiple URLS. I'm assuming I have to use another loop, but I am still learning them.

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

string getKey(const string keyval, size_t start, size_t& second);

using namespace std;

int main()
{
    int count = 0;
    size_t res;
    string url = "https://www.google.com/search?q=where+food+near+me&oq=where+food+near+me&aqs=chrome..69i57j0l5.8995j0j9&sourceid=chrome&ie=UTF-8";
    while(count < 20){
        cout << getKey(url,0, res) << endl;
        while (!(res == url.length()){
        cout << getKey(url,res, res) << endl;
            ++count;
        }
        cout<< res << endl;
        ++count;
   }

    return 0;
}

string getKey(const string keyval, size_t start, size_t& second)
{
    size_t first;
    string result;
    if(start == 0){
        first = keyval.find('&');
    }
    else{
        first = start;
    }
    first = first + 1;
    second = keyval.find('&' , first);
    result = keyval.substr(first, second - first);
    return result;
}

UPDATE

#include <iostream>
#include <fstream>
#include <algorithm>

using namespace std;

namespace helpers {
size_t getDomainName(const string str, string& result);
size_t getKeyVal(const string str, const size_t start_pos, string& result);
bool getKey(const string &keyval, size_t start, size_t& second, string &result);
string getVal(const string keyval);
}
using namespace helpers;


int main() {
    string fileName;
    int count = 0;
    int total_query = 0, total_length = 0, avg_length = 0;
    string URL,str;
    int total_Urls = 0;
    string line;
    string res,key,val;
    cout << "Please input the name of the file: " << endl;
    cin >> fileName;
    ifstream fin;
    fin.open (fileName);
    if (fin.is_open()){
        cout << "File opened successfully...\n";
    }
    else {
        cout << "File failed to open...\n";
        return 0;
    }

    // Finding total URL count...
    for (string URL; fin >> URL;){
       ++total_Urls;
    }
    //cout << total_Urls << endl;
    fin.close();
    fin.open(fileName);

    count = 0;

    //average length of URL
    while (count < total_Urls){
        fin >> str;
       // cout << "The length of the URL: "<<str.length() <<endl;
    total_length += str.length();
        ++count;
    }
    avg_length = total_length / total_Urls;
   // cout << "Average length: "<< avg_length << endl;

    fin.close();
    fin.open(fileName);



    count = 0;

    //average length of query
    while(count < total_Urls){
        fin >> URL;
        getKeyVal(URL, 0, res);
        res = res.substr(2);
        replace(res.begin(), res.end(), '+', ' ');
       // cout << "Test: " << res << endl;
       // cout << "Length of Query: " << res.length() << endl;
        total_query += res.length();
        ++count;

    }
    int avg_query_length = total_query / count;
    //cout << "Average length of query: " << avg_query_length << endl;

    fin.close();
    fin.open(fileName);

    //dealing with options

   /* while(count < 20){
         cout << getKey(url,0, res) << endl;
         while (count < 5){
         cout << getKey(url,res, res) << endl;
             ++count;
         }
         cout<< res << endl;
         ++count;
    } */

    count = 0;
    string value;
    size_t res2 = 0;
    while (count < total_Urls){
        fin >> URL;

    while ((count < 20) && getKey(URL, res2, res2, value)){
        cout << value << endl;
        ++count;
    }
    }

    cout << "Statistics for <" <<fileName << ">" << endl;
    cout << "--------------------------" << endl;
    cout << "Number of Queries: " << total_Urls << endl;
    cout << "Average length of URL: " << avg_length << endl;
//    cout << "Average length of Query String: " << avg_query;

    return 0;
}

namespace helpers {

size_t getDomainName (const string str, string& result){
size_t first, second;
first = str.find('/');
first = str.find('/', first + 1);
second = str.find('/', first + 1);
result = str.substr(first + 1, second - (first + 1));
return second;
}
size_t getKeyVal(const string str, const size_t start_pos, string& result){
    size_t first, second;
    if(start_pos == 0) {
        first = str.find('?');
    }
    else {
        first = start_pos;
    }
    second = str.find('&', first + 1);
    result = str.substr(first + 1, second - (first + 1));
    return second;
}
bool getKey(const string &keyval, size_t start, size_t& second, string &result)
{
    result = "";

    if (start == 0) {
        if ((start = keyval.find('?')) == string::npos)
            return false;
        ++start;
    }
    else if (start >= keyval.size())
        return false;

    size_t end = keyval.find('&', start);
    if (end != string::npos) {
        result = keyval.substr(start, end - start);
        second = end + 1;
    }
    else {
        result = keyval.substr(start);
        second = keyval.size();
    }
    return true;
}

}
string getVal(const string keyval){
    size_t first;
    string result;
    first = keyval.find('=');
    first = first + 1;
    result = keyval.substr(first);
    replace(result.begin(), result.end(), '+', ' ');
    return result;
}


Upvotes: 0

Views: 631

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 597550

You are not taking into account that when the last & is found, a subsequent call to find('&') will return std::string::npos, which is -1, not the string length like you are expecting. So you are not able to return the final key=value pair correctly.

I would suggest changing the function to return a bool if the next key is not found. Then you can break the loop when the function returns false. Upon exit, res should be set to the location of the next token after the found &, not to the & itself.

Try something more like this:

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

bool getKey(const string &keyval, size_t start, size_t& second, string &value);

int main()
{
    int count = 0;
    string url = "https://www.google.com/search?q=where+food+near+me&oq=where+food+near+me&aqs=chrome..69i57j0l5.8995j0j9&sourceid=chrome&ie=UTF-8";
    string value;
    size_t res = 0;
    while ((count < 20) && getKey(url, res, res, value)) {
        cout << value << endl;
        ++count;
    }

    return 0;
}

bool getKey(const string &keyval, size_t start, size_t& second, string &result)
{
    result = "";

    if (start == 0) {
        if ((start = keyval.find('?')) == string::npos)
            return false;
        ++start;
    }
    else if (start >= keyval.size())
        return false;

    size_t end = keyval.find('&', start);
    if (end != string::npos) {
        result = keyval.substr(start, end - start);
        second = end + 1;
    }
    else {
        result = keyval.substr(start);
        second = keyval.size();
    }
    return true;
}

Output:

q=where+food+near+me
oq=where+food+near+me
aqs=chrome..69i57j0l5.8995j0j9
sourceid=chrome
ie=UTF-8

Live Demo

Upvotes: 1

Related Questions