I'm working on a piece of code and encountered a small problem here. In an overall the problem is with a string delimiter and a splitting of a C std::string.
The string that I have is:
std::string nStr =
R"(
"0000:ae:05.2:
Address: 0000:ae:05.2
Segment: 0x0000
")";
Normally the above is way larger and has many more data entries. The delimiter I have set is the ": " as it will be the most common delimiter I have in the data. What I aim to get is 2 strings i.e. string1 = Address and string2 = 0000:ae:05.2 but I also need the 1st line to be treated similarly so basically it all should start from string1 = header and string2 = 0000:ae:05.2
My code looks like that at the moment:
int main(int argc, char* argv[])
{
std::string nStr =
R"(
"0000:ae:05.2:
Address: 0000:ae:05.2
Segment: 0x0000
")";
std::string tLine1="", tLine2="";
//nStr = nStr.erase(nStr.find_last_not_of("\n\r\t"));
const std::string delimiter = ": ", delim2=":";
std::string::size_type pos = nStr.find(delimiter);
std::string::size_type pos2 = nStr.find(delim2);
if(nStr.npos != pos){
tLine2 = nStr.substr(pos 1);
tLine1 = nStr.substr(0, pos);
}
else if(nStr.npos != pos2){
tLine1 = nStr.substr(0, pos2);
tLine2 = "blank";
}
else
std::cout << "Delimiter not specified!\n";
What does it works for the "main" delimiter, the ": " and not for the ":". Also it does not read all the ": " delimiters.
My output would be: tLine1= "0000:ae:05.2: Address tLine2= 0000:ae:05.2 Segment: 0x0000
Any thoughts on how this can be done correctly? Or how to approach this in a better way? Thanks in advance.
CodePudding user response:
The code below does what you want to do.
#include<iostream>
#include<string>
int main(int argc, char* argv[])
{
std::string nStr =
R"(0000:ae:05.2:Address: 0000:ae:05.2 Segment: 0x0000
)";
std::string tLine1 = "", tLine2 = "";
const std::string delimiter = ": ";
size_t pos = 0;
while ((pos = nStr.find(delimiter)) != std::string::npos) {
tLine1 = nStr.substr(0, pos);
nStr.erase(0, pos delimiter.length());
tLine2 = nStr;
break;
}
std::cout << "tLine1 = " << tLine1<<"\n";
std::cout << "tLine2 = " << tLine2<<"\n";
}
Output:
tLine1 = 0000:ae:05.2:Address
tLine2 = 0000:ae:05.2 Segment: 0x0000
CodePudding user response:
Okay, from what I can understand from your comments, you want to split the original string into lines, and then split the individual lines by using ":" as a delimiter. With the exception for the first line, which only has one value. Thus the resulting pair for this line should have the value from the line and the string literal "header".
#include <iostream>
#include <string>
#include <utility>
auto splitLine(const std::string& line) {
using namespace std::string_literals;
auto delimiterPos = line.find(": ");
if (delimiterPos != std::string::npos) {
return std::make_pair(line.substr(0, delimiterPos),
line.substr(delimiterPos 2));
}
return std::make_pair(line.substr(1, line.size() - 2), "header"s);
}
int main(int argc, char* argv[]) {
std::string nStr =
R"(
"0000:ae:05.2:
Address: 0000:ae:05.2
Segment: 0x0000
")";
std::size_t newLinePos;
do {
newLinePos = nStr.find("\n");
std::string line = nStr.substr(0, newLinePos);
nStr = nStr.substr(newLinePos 1);
// To ignore empty lines and the last line that just contains a double quote
if (line.size() == 0 || line == "\"") {
continue;
}
auto lines = splitLine(line);
std::cout << "line1: " << lines.first << "\n";
std::cout << "line2: " << lines.second << "\n";
} while (newLinePos != std::string::npos);
}
I'm not 100% sure which of the part of each line is considered the first value and which is the second. It seems you're switching this up between the question and each comment. But you should be able to change that according to your desire.
Another aspect I did not fully grasp is the layout of the original string. It seems to start with an new line character. And the end with a new line followed by a double quote. I had to catch those specifically.
And the first "header" line begins with a double quote and ends with a colon. I just expect this always to be the case and removed the first and last character from said line.
It would help if we had a better example for the incoming data.