I would like to check the following:
If the last character appended to the stringstream is a comma.
If it is remove it.
std::stringstream str;
str << "["
//loop which adds several strings separated by commas
str.seekp(-1, str.cur); // this is to remove the last comma before closing bracket
str<< "]";
The problem is if nothing is added in the loop, the opening bracket is removed from the string. So I need a way to check whether the last character is a comma. I did that like this:
if (str.str().substr(str.str().length() - 1) == ",")
{
str.seekp(-1, rteStr.cur);
}
But I don't feel very good about this. Is there a better way to do this?
About the loop:
Loop is used to tokenize a set of commands received through sockets and format it to send to another program through another socket. Each command ends with an OVER flag.
std::regex tok_pat("[^\\[\\\",\\]]+");
std::sregex_token_iterator tok_it(command.begin(), command.end(), tok_pat);
std::sregex_token_iterator tok_end;
std::string baseStr = tok_end == ++tok_it ? "" : std::string(*tok_it);
while (baseStr == "OVER")
{
//extract command parameters
str << "extracted_parameters" << ","
}
The way I often deal with these loops where you want to put something like a space or a comma between a list of items is like this:
int main()
{
// initially the separator is empty
auto sep = "";
for(int i = 0; i < 5; ++i)
{
std::cout << sep << i;
sep = ", "; // make the separator a comma after first item
}
}
Output:
0, 1, 2, 3, 4
If you want to make it more speed efficient you can output the first item using an if() before entering the loop to output the rest of the items like this:
int main()
{
int n;
std::cin >> n;
int i = 0;
if(i < n) // check for no output
std::cout << i;
for(++i; i < n; ++i) // rest of the output (if any)
std::cout << ", " << i; // separate these
}
In your situation the first solution could work like this:
std::regex tok_pat("[^\\[\\\",\\]]+");
std::sregex_token_iterator tok_it(command.begin(), command.end(), tok_pat);
std::sregex_token_iterator tok_end;
std::string baseStr = tok_end == ++tok_it ? "" : std::string(*tok_it);
auto sep = ""; // empty separator for first item
while (baseStr == "OVER")
{
// extract command parameters
str << sep << "extracted_parameters";
sep = ","; // make it a comma after first item
}
And the second (possibly more time efficient) solution:
std::regex tok_pat("[^\\[\\\",\\]]+");
std::sregex_token_iterator tok_it(command.begin(), command.end(), tok_pat);
std::sregex_token_iterator tok_end;
std::string baseStr = tok_end == ++tok_it ? "" : std::string(*tok_it);
if (baseStr == "OVER")
{
// extract command parameters
str << "extracted_parameters";
}
while (baseStr == "OVER")
{
// extract command parameters
str << "," << "extracted_parameters"; // add a comma after first item
}
Related
I'm a beginner programmer trying to have a user enter an email in a text field. In the text field I would like to:
A) Ensure the user has entered an # symbol somewhere in the field
B) Ensure the user has entered a . somewhere after their # symbol
Is there some way to do this? I'm having a hard time looking for my own answers online because of how specific it seems.
Thanks for any help!
You can use std::string:
std::string::size_type position = text_field.find(special_char);
if (position != std::string::npos)
{
// special char is found.
if (position + 1 < text_field.length())
{
if (text_field[position + 1] == specific_char)
{
// Specific char found.
}
}
}
You may want to make a copy of the text field data type into a std::string before using the above code.
To check for a specific character, use
std::string text = "whatever text # something.com";
auto pos = std::find(text.begin(), text.end(), '#');
If '#' appears somewhere in text, pos will point at the location of the first occurrence.
Having done that, to search for another character that follows the first one, just use the same approach, starting at the position of the first character:
auto res = std::find(pos, text.end(), '.');
If both searches succeeded, res will point at the first '.' after the first '#'. If either search failed, it will point past the end of the string:
if (res == text.end())
std::cout << "match failed\n";
else
std::cout << "success\n";
#include <iostream>
#include <string>
int main()
{
std::string email;
std::cin >> email;
bool at_the_rate = false;
bool dot = false;
for (int i = 0; i < email.size(); ++i) {
if (email[i] == '#')
at_the_rate = true;
for (int j = i+1; j < email.size(); ++j)
if(email[j] == '.')
dot = true;
}
if ( at_the_rate && dot)
std::cout << "this is valid email." << std::endl;
else
std::cout << "this is not a valid email." << std::endl;
return 0;
}
Meme
If my memory serves me, then the true regular that checks for the validity of E-Mail takes 100500 lines, you decide you really need to check whether the e-mail is valid, or does it just meet your deep subjective requirements?
But i still tried to make it a REGEX.
#include <iostream>
#include <regex>
#include <string>
bool CheckEmail(const std::string &str)
{
return std::regex_match(str, std::regex("([\\w-\\.]+)#((?:\\w+\\.)+)([a-zA-Z]{2,4})"));
}
int main()
{
std::cout << std::boolalpha << CheckEmail("abra#a.ruuqq") << std::endl;
}
will be useful ...
https://learn.microsoft.com/en-us/cpp/standard-library/regex-functions?view=msvc-160
https://en.cppreference.com/w/cpp/regex
https://www.youtube.com/watch?v=9K4N6MO_R1Y
Similar to Parse comma-separated ints/int-ranges in C++,
I want a regex to extract edges from a string: (1,2,1) (2,4,5) (1,4,3) (3,4,10) (3,6,2) (3,5,3) (6,7,6) (4,7,4) where (Node1 number, Node2 number, distance).
I currently am using: std::regex reg_edge("\(.*?\,.*?\,.*?\)"); which does not work (as in not a single match is found).
Since this can also be an XY-Problem, I will state what I want to do: I want the user to enter edges of the graph when creating the graph.
Please suggest a correct regex, or maybe, a better way altogether.
My current code:
void Graph::setEdges() {
std::string edge_str;
std::getline(std::cin, edge_str);
std::istringstream iss(edge_str);
edge_str.clear();
while (iss >> edge_str) {
std::regex reg_edge("\(.*?\,.*?\,.*?\,\)");
auto reg_begin = std::sregex_iterator(edge_str.begin(), edge_str.end(), reg_edge);
auto reg_end = std::sregex_iterator();
for (std::sregex_iterator reg_it = reg_begin; reg_it != reg_end; reg_it++) {
std::smatch it_match = *reg_it;
}
}
}
You can use the regex \((\d+),(\d+),(\d+)\) with std::sregex_iterator. Note that you have to escape ( and ) to match against them literally. ALso, using a raw literal string makes it easier with regexes.
Then extract each matching group using operator[]. Group 0 is always the whole group, so you want groups 1, 2, and 3 in your case.
std::regex reg(R"(\((\d+),(\d+),(\d+)\))");
std::string str = "(1,2,1) (2,4,5) (1,4,3) (3,4,10) (3,6,2) (3,5,3) (6,7,6) (4,7,4)";
auto start = std::sregex_iterator(str.begin(), str.end(), reg);
auto end = std::sregex_iterator{};
for (std::sregex_iterator it = start; it != end; ++it)
{
std::cout << "Node1 = " << (*it)[1] << ", Node2 = " << (*it)[2]
<< ", Distance = " << (*it)[3] << std::endl;
}
Here's a demo.
Trying to find a line by one word in a vector.
For example:
In a file some data,like:
ctrl+a move,find
ctrl+c copy,group
ctrl+z take,give
all letters are small.
Then I tried to read a file in vector - it's okay
Then the user want to input : move
**I want that if the user input move, I find a line in vector,which has the word move and do something with this line.(for example: erase)*
But what do I do wrong , because my loop stops on zero and it reads only the first string of a file?
code is below:
void HotMap::test(std::string str)
{
std::string line;
std::vector<std::string> vec_keys;
std::string file_name_keys("read_keys.txt");
std::ifstream file_keys(file_name_keys, std::ios::in);
std::vector<std::string>::iterator iter_vec;
while (std::getline(file_keys, line))
{
for (auto & c : line) c = tolower(c);
vec_keys.push_back(line);
}
for (int i = 0; i < 3; i++)
{
vec_keys[i].find(str);
if (vec_keys[i].find(str))
{
std::string found_str;
std::cout << "Found:" << vec_keys[i];
//Just help to find the line.....
break;
}
}
}
Read the ref of string::find:
Return Value
The position of the first character of the first match. If no matches were found, the function returns string::npos.
So, try this instead:
if (vec_keys[i].find(str) != std::string::npos)
std::cout << "Found:" << vec_keys[i];
I have a std::string, how can i replace : character with %%?
std::replace( s.begin(), s.end(), ':', '%%' );
this code above doesn't work:
error no instance matches the arguement list
Thanks!
Unfortunately, there is no way to replace all : characters in one shot. But you can do it in a loop, like this:
string s = "quick:brown:fox:jumps:over:the:lazy:dog";
int i = 0;
for (;;) {
i = s.find(":", i);
if (i == string::npos) {
break;
}
s.replace(i, 1, "%%");
}
cout << s << endl;
This program prints
quick%%brown%%fox%%jumps%%over%%the%%lazy%%dog
If you need to replace only the first colon, then use the body of the loop by itself, without the loop around it.
I am using the substr() function, however it's not working. My code is below
std::string s1 = ".V/123\n"
".V/233\n";
std::string ss;
if(s1.substr(0,3) == ".V/")
{
ss = s1.substr(3);
std::cout << ss;
} else {
std::cout << "INCORRECT" << std::endl;
}
The output is 123.V/123
Shouldn't it be:
123
123
Could someone tell me where I am going wrong please?
Your string contains 2 lines. Doing ".V/123\n" ".V/223\n" will do the same as ".V/123\n.V/223\n". Either split that up into separate variables or an array. What your substr(3) is doing is extracting all the characters in the string from the 4th character to the end, so 'ss' is getting set to "123\n.V/223\n". This is what you're seeing.
What you want is something like this
std::string s1[2] = { ".V/123\n", ".V/233\n"};
std::string ss;
for (int i = 0; i < 2; ++i) {
if (s1[i].substr(0,3) == ".V/") {
ss = s1[i].substr(3);
std::cout << ss;
} else {
std::cout << "INCORRECT" << std::endl;
}
}
The output from your code should be:
123
.V/233
<empty line>
and this is exactly what it prints on my machine.
First of all notice the second 3 digits are 233(I guess that is a typo), not 123. All substr(3) does is: it removes the first 3 characters from your string. No reason that .V/ should be removed.
The first strange thing I see is the init of s1
std::string s1 = ".V/123\n"
".V/233\n";
if you just want it to be ".V/123\n", you should declare it as:
std::string s1 = ".V/123\n";
The second strange thing is the second call to substr, only defines the position, so you will get from the position to the end of the string, so that works as advertised. I added a reference for you below.
reference:
http://www.cplusplus.com/reference/string/string/substr/
ss = s1.substr(3).substr(0,3);
this should work