Why Boost:Regex not found all results as expected? - c++

I have a c++ sample and i want to find all queries inside a relative uri
(like: /class?class_id=-1&course_ref=1&student_ref=2&score_ref=1). If it works, i would find all results: ( "class_id=-1" "course_ref=1" "student_ref=2" "score_ref=1: ) but only "course_ref=1" was found! Here's my code:
#include <iostream>
#include <boost/regex.hpp>
int main() {
std::string url = "/class?class_id=-1&course_ref=1&student_ref=2&score_ref=1";
const boost::regex queries_pattern("(?<=(\?|\&))[a-zA-Z0-9_=-]+");
boost::smatch queries_result;
boost::regex_search(url, queries_result, queries_pattern);
std::string results("");
for (unsigned int i = 0; i <= queries_result.size(); i++) {
if (!queries_result[i].str().empty())
std::cout << queries_result[i] << std::endl;
}
std::cin.get();
}
I also tried other regex patterns (without look-behind) but non of them worked. Also i tested std::regex and Boost:Xpressive and no result extracted.
Does anyone knows why this fails?? Or there's a different solution? Thanks.

I don't know why but i must loop on iterator not directly on results. Here's the worked code:
#include <iostream>
#include <boost/regex.hpp>
int main() {
std::string url = "/class?class_id=-1&course_ref=1&student_ref=2&score_ref=1";
const boost::regex pattern("[a-zA-Z0-9_=-]+((?=&)|(?=$))");
boost::sregex_token_iterator iter(url.begin(), url.end(), pattern, 0);
boost::sregex_token_iterator end;
for (; iter != end; ++iter) {
std::cout << *iter << '\n';
}
std::cin.get();
}
Thank you "the fourth bird" for your correct point.

Related

Get last part of URL

How would I get the last part of a URL?
Say the variable url is https://somewhere.com/stuff/hello.
How would I get hello from this?
Using rfind and substr
Maybe with
#include <iostream>
#include <string>
int main() {
std::string url{"https://somewhere.com/stuff/hello"};
std::cout << url.substr(url.rfind('/')+1);
return 0;
}
But only, if you have a / in front of the last part
#include <iostream>
#include <string>
int main() {
const std::string url("https://somewhere.com/stuff/hello");
const std::size_t indexLastSeparator = url.find_last_of("/");
if (indexLastSeparator != std::string::npos)
{
const std::string lastPartUrl = url.substr(indexLastSeparator+1); // +1 to not keep /
std::cout << lastPartUrl << '\n'; // print "hello"
}
}
With find_last_of() and substr()
references :
https://en.cppreference.com/w/cpp/string/basic_string/find_last_of
https://en.cppreference.com/w/cpp/string/basic_string/substr

How to check if a string contains punctuation c++

I am attempting to iterate over a string to check for punctuation. I've tried to use ispunct() but am receiving an error that there is no matching fucntion for call to ispunct. Is there a better way to implement this?
for(std::string::iterator it = oneWord.begin(); it != oneWord.end(); it++)
{
if(ispunct(it))
{
}
}
Is there a better way to implement this?
Use std::any_of:
#include <algorithm>
#include <cctype>
#include <iostream>
int main()
{
std::string s = "Contains punctuation!!";
std::string s2 = "No puncuation";
std::cout << std::any_of(s.begin(), s.end(), ::ispunct) << '\n';
std::cout << std::any_of(s2.begin(), s2.end(), ::ispunct) << '\n';
}
Live Example
it is an iterator; it points to a character in a string. You have to dereference it to get the thing it points to.
if(ispunct(static_cast<unsigned char>(*it)))

most efficient way to parse a string using c++ features

this might be a stupid question (I hope not) but it caught my mind and I'm trying to figure it out. What is the most efficient way to parse a string using c++ features?
I appreciate everyone's comments as I, am I'm sure everyone else is too, to become a better programmer!
Here is how I would do it right now with my current knowledge:
#include <iostream>
#include <string>
using std::cout;
using std::string;
using std::endl;
void parseLine(string &line)
{
constexpr char DELIMITER_ONE = '|';
constexpr char DELIMITER_TWO = '[';
for (int i = 0; i < line.length(); i++)
{
if (line[i] == DELIMITER_ONE || line[i] == DELIMITER_TWO)
{
line.erase(i, 1);
}
}
cout << line << endl;
}
int main()
{
std::string testString = "H|el[l|o|";
parseLine(testString);
system("pause");
return 0;
}
line.erase(
std::remove_if(line.begin(), line.end(),
[](char c) { return c == DELIMITER_ONE || c == DELIMITER_TWO; }
),
line.end()
);
See also: erase-remove idiom
One more way is to use the boost regex library. Check the below code:
#include <iostream>
#include <string>
#include <boost/regex.hpp>
int main(){
std::string testString = "H|el[l|o|";
boost::regex rx("\\||\\[");
std::string replace = "";
std::string out = boost::regex_replace(testString, rx, replace);
std::cout << out << std::endl;
}
C++14 now includes regular expressions standard:
#include <iostream>
#include <string>
#include <regex>
std::string parseLine(const std::string& line);
int main() {
std::string testString = "H|el[l|o|";
std::string result = parseLine(testString);
std::cout << result << std::endl;
system("pause");
return 0;
}
std::string parseLine(const std::string& line) {
std::string input_string;
std::string result;
std::smatch sm;
std::regex r("([a-zA-Z]+)");
for(input_string = line; std::regex_search(input_string, sm, r); input_string = sm.suffix()) {
result.append(sm[0].str());
}
return result;
}

boost::regex matches[] c++

I have a code that returns all matches from a regex but i can't use matches, for example i want to cout just the second result like match[1] or match[2]
std::string text("5345345345334 456456454353");
boost::regex regex("[0-9]{10}");
boost::sregex_token_iterator iter(text.begin(), text.end(),regex,0);
boost::sregex_token_iterator end;
for( ; iter != end; ++iter ) {
std::cout<<*iter<<'\n';
is there any way to convert *iter to matches[] so i can use each match ? thanks
Here is the correct answer:
just create the std::vector from iterators you have:
std::vector<std::string> v(iter, end);
Full code:
#include <stdlib.h>
#include <string>
#include <iostream>
#include <boost/regex.hpp>
#include <vector>
int main(int argc, char* argv[]) {
std::string text("5345345345334 456456454353");
boost::regex regex("[0-9]{10}");
boost::sregex_token_iterator iter(text.begin(), text.end(),regex,0);
boost::sregex_token_iterator end;
std::vector<std::string> v(iter, end);
std::cout << "0: " << v[0] << ", 1: " << v[1] << std::endl;
return EXIT_SUCCESS;
}
And the output is:
0: 5345345345, 1: 4564564543

find pattern in string regular expression c++

I have the following string : E:\501_Document_60_1_R.xml
I am trying to find the pattern "_R"
I am using the following : boost::regex rgx("[R]");
But it's not working : "Empty Match"
thank you.
Code:
vector<string> findMono(string s)
{
vector<string> vec;
boost::regex rgx("[R]");
boost::smatch match;
boost::sregex_iterator begin {s.begin(), s.end(), rgx},
end {};
for (boost::sregex_iterator& i = begin; i != end; ++i)
{
boost::smatch m = *i;
vec.push_back(m.str());
}
return vec;
}
int maint()
{
vector<string> m = findMono("E:\501_Document_60_1_R.xml");
if(m.size() > 0) cout << "Match" << endl;
else cout << "No Match" << endl;
return 0;
}
As we discussed in the comments, "_R" will technically work for your regular expression given your current data set.
However, I'd strongly consider something more sophisticated to avoid running into problems in the event that your paths contain the sequence "_R" elsewhere. It's fairly easy to protect yourself against that problem, it's good general practice, and it will most likely avoid bugs in the future.
Here is a very basic working example:
#include <iostream>
#include <string>
#include <vector>
#include <boost/regex.hpp>
std::vector<std::string> findMono(const std::string& path)
{
boost::regex rgx("_R");
boost::sregex_iterator begin {path.begin(), path.end(), rgx}, end {};
std::vector<std::string> matches;
for (boost::sregex_iterator& i = begin; i != end; ++i) {
matches.push_back((*i).str());
}
return matches;
}
int main(int argc, char * argv[])
{
const std::string path = "E:\\501_Document_60_1_R.xml";
const std::vector<std::string>& matches = findMono(path);
for (const auto& match : matches) {
std::cout << match << std::endl;
}
return 0;
}