I'm building this webcrawler here. This error occurs to me when I start debugging and sends me to memcpy.asm or xstring or dbgdel.cpp files showing me different lines of these files every time.
I was wondering if the code is wrong somehow. I started thinking I am accessing memory blocks that I shouldn't. Here is some code. I hope you can help.
The idea is to iterate through httpContent and get all the URLs from the <a> tags. I am looking for href=" in the beginning and then for the next ". What is in between I am trying to put in temp, then pass the content of temp to an array of strings.
struct Url
{
string host;
string path;
};
int main(){
struct Url website;
string href[100];
website.host = "crawlertest.cs.tu-varna.bg";
website.path = "";
string httpContent = downloadHTTP(website);
for(unsigned int i = 0; i <= httpContent.length()-7; i++){
char c = httpContent[i];
if(c == 'h'){
c = httpContent[i+1];
if(c == 'r'){
c = httpContent[i+2];
if(c == 'e'){
c = httpContent[i+3];
if(c == 'f'){
c = httpContent[i+4];
if(c == '='){
c = httpContent[i+5];
if(c == '\"'){
i+=6;
c = httpContent[i];
string temp = "";
while(c!='\"'){
i++;
c = httpContent[i];
temp+= c;
}
href[i] = temp;
temp = "";
cout<<href[i]<<endl;
}}}}}}
}
system("pause");
return 0;
}
UPDATE
I edited the =, now ==
I am also stopping the iterations 7 positions earlier so the 'if's should not be problem.
I am getting the same errors though.
Use std::vector< std::string > href; to store your result.
With string::find you can find sequence in strings and with string::substr you can extract them from string.
#include <vetor>
#include <string>
struct Url
{
string host;
string path;
};
int main(){
struct Url website;
website.host = "crawlertest.cs.tu-varna.bg";
website.path = "";
std::string httpContent = downloadHTTP(website);
std::vector< std::string > href;
std::size_t pos = httpContent.find("href="); // serach for first "href="
while ( pos != string::npos )
{
pos = httpContent.find( '"', pos+5 ); // serch for '"' at start
if ( pos != string::npos )
{
std::size_t posSt = pos + 1;
pos = httpContent.find( '"', posSt ); // search for '"' at end
if ( pos != string::npos )
{
href.push_back( httpContent.substr( posSt, pos - posSt ) ); // extract ref and append to result
pos = httpContent.find( "href=", pos+1 ); // search for next "href="
}
}
}
system("pause");
return 0;
}
Related
C++ question:
I have the query in txt like this:
CUSTOMER_ID=4155&ORDER_ITEM_TYPE_ID=1&ORDER_ITEM_TYPE_NAME=Product&ORDER_ITEM_SKU=&ORDER_CURRENCY_CODE=UAH
How can I get these fields to make it look nearly like:
Customer_ID: 4155
ORDER_ITEM_TYPE_ID: 1
// and etc...
I know there is a separator "&" between each field, but I don't know how to do it properly.
Use methods of std::string like find,substr. Example:
const std::string field = "CUSTOMER_ID=4155&ORDER_ITEM_TYPE_ID=1&ORDER_ITEM_TYPE_NAME=Product&ORDER_ITEM_SKU=&ORDER_CURRENCY_CODE=UAH";
const char separator = '&';
const char equal = '=';
std::string::size_type cur = 0;
while ( cur != std::string::npos )
{
std::string name;
std::string value;
std::string::size_type newPos = field.find(equal, cur);
if ( newPos != std::string::npos )
{
name = field.substr( cur, newPos - cur );
cur = newPos + 1;
newPos = field.find(separator, cur);
value = field.substr( cur, ( newPos == std::string::npos ) ? std::string::npos : newPos - cur );
cur = ( newPos == std::string::npos ) ? std::string::npos : newPos + 1;
std::cout << name << ": " << value << std::endl;
}
else
{
break;
}
}
try
`char str[10][20];
int len = 0;
int count = 0;
while((c = string[i])!= EOC )
/* EOC : End of Character */
{
if (c == '&') {
str[count][len] = '\0';
len = 0;
count++;
continue;
}
str[count][len] = c;
len++;
}
Replace all '&' with replace and then when you write the data after this back into a file it's formated as requested.
std::ifstream infile("thefile.txt");
while (std::getline(infile, line)) //Read File line by line
{
std::replace( line.begin(), line.end(), '&', '\0'); // replace all '&' to '\0'
cout << line << endl;
}
I want to parse relatively simple registry file format, let's assume it's plain ascii, saved in old REGEDIT4 format. I want to parse it using standard c++ regex class or function (preferably no boost). As an input data it could take for example sample file like this:
REGEDIT4
[HKEY_LOCAL_MACHINE\SOFTWARE\MyCompany\ConfigurationData\v1.0]
[HKEY_LOCAL_MACHINE\SOFTWARE\MyCompany\ConfigurationData\v1.0\General]
"SettingDword"=dword:00000009
"Setting1"="Some string 1"
"SettingString2"="my String"
[HKEY_LOCAL_MACHINE\SOFTWARE\MyCompany\ConfigurationData\v1.0\Networking]
"SettingDword2"=dword:00000002
"Setting2"="Some string 2"
"SettingString3"="my String2"
What I have briefly analyzed - scanning multiple [] can be done using for example cregex_token_iterator class, but main problem is that it is working in opposite way, which I want to use it. I want to start matching pattern like this: regex re("(\\[.*?\\])"), but token iterator returns all strings, which were not matched, which does sounds kind silly to me.
Basically I would like to match first whole section (\\[.*?\\])(.*?\n\n), and then pick up registry path first, and key-values next - then split using regex key-value pairs.
It's really incredible that in C# it's relatively easy to write regex matcher like this, but I would prefer go with C++, as it's native, does not have performance and assembly unload problems.
Finally cross analyzed - it's possible to use regex_search, but search needs to be retried by continuing from next char* after found pattern.
Below is almost complete example to load .reg file at run-time, I'm using MFC's CString, because it's slightly easier to use than std::string and portability is not needed currently.
#include "stdafx.h"
#include <afx.h> //CFile
#include "TestRegex.h"
#include <fstream>
#include <string>
#include <regex>
#include <map>
CWinApp theApp;
using namespace std;
typedef enum
{
eREG_DWORD = REG_DWORD,
eREG_QWORD = REG_QWORD,
eREG_BINARY = REG_BINARY,
eREG_SZ = REG_SZ
}eRegType;
class RegVariant
{
public:
eRegType type;
union
{
DWORD dw;
__int64 qw;
};
CStringA str;
};
class RegKeyNode
{
public:
// Paths to next nodes
map<CStringA, RegKeyNode> keyToNode;
// Values of current key
map<CStringA, RegVariant> keyValues;
};
map<HKEY, RegKeyNode> g_registry;
int char2int(char input)
{
if (input >= '0' && input <= '9')
return input - '0';
if (input >= 'A' && input <= 'F')
return input - 'A' + 10;
if (input >= 'a' && input <= 'f')
return input - 'a' + 10;
return 0;
}
void hexToBin( const char* hex, CStringA& bin, int maxSize = -1 )
{
int size = (strlen(hex) + 1)/ 3;
if(maxSize != -1 && size > maxSize)
size = maxSize;
unsigned char* buf = (unsigned char*)bin.GetBuffer(size);
for( int i = 0; i < size; i++ )
buf[i] = char2int( hex[ i*3 ] ) * 16 + char2int(hex[i * 3 + 1]);
bin.ReleaseBuffer();
}
int main()
{
HMODULE hModule = ::GetModuleHandle(nullptr);
AfxWinInit(hModule, nullptr, ::GetCommandLine(), 0);
//
// Load .reg file.
//
CString fileName = L"test1.reg";
CStringA file;
CFile cfile;
if (cfile.Open(fileName, CFile::modeRead | CFile::shareDenyNone))
{
int len = (int)cfile.GetLength();
cfile.Read(file.GetBuffer(len), len);
file.ReleaseBuffer();
}
cfile.Close();
file.Replace("\r\n", "\n");
const char* pbuf = file.GetBuffer();
regex reSection("\\[(.*?)\\]([^]*?)\n\n");
regex reLine("^\\s*\"(.*?)\"\\s*=\\s*(.*)$");
regex reTypedValue("^(hex|dword|hex\\(b\\)):(.*)$");
regex reStringValue("^\"(.*)\"$" );
cmatch cmSection, cmLine;
//
// For each section:
//
// [registry path]
// "value1"="value 1"
// "value2"="value 1"
//
while( regex_search(pbuf, pbuf + strlen(pbuf), cmSection, reSection) )
{
CStringA path = cmSection[1].str().c_str();
string key_values = cmSection[2].str();
const char* pkv = key_values.c_str();
int iPath = 0;
CStringA hkeyName = path.Tokenize("\\", iPath).MakeUpper();
RegKeyNode* rnode;
if( hkeyName.Compare("HKEY_LOCAL_MACHINE") == 0 )
rnode = &g_registry[HKEY_LOCAL_MACHINE];
else
rnode = &g_registry[HKEY_CURRENT_USER]; // Don't support other HKEY roots.
//
// Locate path where to place values.
//
for( ; hkeyName = path.Tokenize("\\", iPath); )
{
if( hkeyName.IsEmpty() )
break;
rnode = &rnode->keyToNode[hkeyName];
}
//
// Scan "key"="value" pairs.
//
while( regex_search(pkv, pkv+strlen(pkv), cmLine, reLine ))
{
CStringA key = cmLine[1].str().c_str();
string valueType = cmLine[2].str();
smatch cmTypeValue;
RegVariant* rvValue = &rnode->keyValues[key];
//
// Extract type and value.
//
if(regex_search(valueType, cmTypeValue, reTypedValue))
{
string type = cmTypeValue[1].str();
string value = cmTypeValue[2].str();
if( type == "dword")
{
rvValue->type = eREG_DWORD;
rvValue->dw = (DWORD)strtoul(value.c_str(), 0, 16);
}
else if (type == "hex(b)")
{
rvValue->type = eREG_QWORD;
rvValue->qw = 0;
if( value.size() == 8 * 2 + 7 )
{
CStringA v;
hexToBin(value.c_str(), v, sizeof(__int64));
rvValue->qw = *((__int64*)v.GetBuffer());
}
} else //if (type == "hex")
{
rvValue->type = eREG_BINARY;
hexToBin(value.c_str(), rvValue->str);
}
} else if( regex_search(valueType, cmTypeValue, reStringValue))
{
rvValue->type = eREG_SZ;
rvValue->str = cmTypeValue[1].str().c_str();
}
pkv = cmLine[2].second;
} //while
pbuf = cmSection[2].second;
} //while
return 0;
}
I am programming some automated test equipment (ATE) and I'm trying to extract the following values out of an example response from the ATE:
DCRE? 1,
DCRE P, 10.3, (pin1)
DCRE F, 200.1, (pin2)
DCRE P, 20.4, (pin3)
From each line, I only care about the pin and the measured result value. So for the case above, I want to store the following pieces of information in a map<std::string, double> results;
results["pin1"] = 50.3;
results["pin2"] = 30.8;
results["pin3"] = 70.3;
I made the following code to parse the response:
void parseResultData(map<Pin*, double> &pinnametoresult, string &datatoparse) {
char *p = strtok((char*) datatoparse.c_str(), " \n");
string lastread;
string current;
while (p) {
current = p;
if(current.find('(') != string::npos) {
string substring = lastread.substr(1);
const char* last = substring.c_str();
double value = strtod(last, NULL);
unsigned short number = atoi(current.substr(4, current.size()-2).c_str());
pinnametoresult[&pinlookupmap[number]] = value;
}
lastread = p;
p = strtok(NULL, " \n");
}
}
It works, but it's not very efficient. Is there a way to make the function more efficient for this specific case? I don't care about the DCRE or P/F value on each line. I thought about using Boost regex library, but not sure if that would be more efficient.
In order to make this a bit more efficient, try to avoid copying. In particular, calls to substring, assignments etc can cause havoc on the performance. If you look at your code, you will see that the content of datatoparse are repeatedly assigned to lastread and current, each time with one line less at the beginning. So, on average you copy half of the original string times the number of lines, making just that part an O(n^2) algorithm. This isn't relevant if you have three or four line (not even on 100 lines!) but if you have a few more, performance degrades rapidly.
Try this approach instead:
string::size_type p0 = 0;
string::size_type p1 = input.find('\n', p0);
while (p1 != string::npos) {
// extract the line
string line = input.substr(p0, p1 - p0);
// move to the next line
p0 = p1 + 1;
p1 = input.find('\n', p0);
}
Notes:
Note that the algorithm still copies all input once, but each line only once, making it O(n).
Since you have a copy of the line, you can insert '\0' as artificial separator in order to give a substring to e.g. atoi() or strtod().
I'm not 100% sure of the order of parameters for string::find() and too lazy to look it up, but the idea is to start searching at a certain position. Look at the various overloads of find-like functions.
When handling a line, search the indices of the parts you need and then extract and parse them.
If you have line fragments (i.e. a partial line without a newline) at the end, you will have to modify the loop slightly. Create tests!
This is what I did:
#include <cstdlib>
#include <string>
#include <vector>
#include <unordered_map>
#include <sstream>
#include <iostream>
using namespace std;
struct Pin {
string something;
Pin() {}
};
vector<Pin*> pins = { new Pin(), new Pin(), new Pin() };
typedef unordered_map<Pin*, double> CONT_T;
inline bool OfInterest(const string& line) {
return line.find("(") != string::npos;
}
void parseResultData(CONT_T& pinnametoresult, const string& datatoparse)
{
istringstream is(datatoparse);
string line;
while (getline(is, line)) {
if (OfInterest(line)) {
double d = 0.0;
unsigned int pinid;
size_t firstComma = line.find(",")+2; // skip space
size_t secondComma = line.find(",", firstComma);
istringstream is2(line.substr(firstComma, secondComma-firstComma));
is2 >> d;
size_t paren = line.find("(")+4; // skip pin
istringstream is3(line.substr(paren, (line.length()-paren)-1));
is3 >> pinid;
--pinid;
Pin* pin = pins[pinid];
pinnametoresult[pin] = d;
}
}
}
/*
*
*/
int main(int argc, char** argv) {
string datatoparse = "DCRE? 1, \n"
"DCRE P, 10.3, (pin1)\n"
"DCRE F, 200.1, (pin2)\n"
"DCRE P, 20.4, (pin3)\n";
CONT_T results;
parseResultData(results, datatoparse);
return 0;
}
Here's my final result. Does not involve any copying, but it will destroy the string.
void parseResultData3(map<std::string, double> &pinnametoresult, std::string &datatoparse) {
char* str = (char*) datatoparse.c_str();
int length = datatoparse.size();
double lastdouble = 0.0;
char* startmarker = NULL; //beginning of next pin to parse
for(int pos = 0; pos < length; pos++, str++) {
if(str[0] == '(') {
startmarker = str + 1;
//get previous value
bool triggered = false;
for(char* lookback = str - 1; ; lookback--) {
if(!triggered && (isdigit(lookback[0]) || lookback[0] == '.')) {
triggered = true;
*(lookback + 1) = '\0';
}
else if(triggered && (!isdigit(lookback[0]) && lookback[0] != '.')) {
lastdouble = strtod(lookback, NULL);
break;
}
}
}
else if(startmarker != NULL) {
if(str[0] == ')') {
str[0] = '\0';
pinnametoresult[startmarker] = lastdouble;
startmarker = NULL;
}
if(str[0] == ',') {
str[0] = '\0';
pinnametoresult[startmarker] = lastdouble;
startmarker = str + 1;
}
}
}
}
I have one array like this:
static WCHAR FilesToShow[][100] = { { L"start.cmd" },{ L"image.xml" }, { L"xyz" }};
as you see that there is "xyz" which I have to replace with some unique name. For this I have to read image.xml file.
Please can you tell me how can I do this.
I wrote a method like this:
PRIVATE WCHAR GetSystemName(WCHAR *pName)
{
WCHAR line;
wfstream in("image.xml");
WCHAR tmp;
bool begin_tag = false;
while (getline(in,line))
{
// strip whitespaces from the beginning
for (int i = 0; i < line.length(); i++)
{
if (line[i] == ' ' && tmp.size() == 0)
{
}
else
{
tmp += line[i];
}
}
if (wcswcs(tmp,"<SystemPath>") != NULL)
{
???????? how to get "vikash" from here <SystemPath>C:\Users\rs_user\Documents\RobotStudio\Systems\vikash</SystemPath>
}
else
{
continue;
}
}
return tmp;
}
I'm getting exception for wfstream, getline and line.length() method.
I have included fstream.h header file but I think It's not supported in COM.
Please help me how to solve this issue without parsing xml file.
If your xml-file is simple enough so that there is only a single tag with given name, you could do it like this:
#include <string>
#include <sstream>
#include <iostream>
std::wstring get_value(std::wistream & in, std::wstring const & tagname)
{
std::wstring text = std::wstring(std::istreambuf_iterator<std::wstring::value_type>(in),
std::istreambuf_iterator<std::wstring::value_type>());
std::wstring start_tag = L"<" + tagname + L">";
std::wstring end_tag = L"</" + tagname + L">";
std::wstring::size_type start = text.find(start_tag);
if (start == std::wstring::npos)
{
throw 123;
}
start += start_tag.length();
std::wstring::size_type end = text.find(end_tag);
if (end == std::wstring::npos)
{
throw 123;
}
return text.substr(start, end - start);
}
std::wstring get_substr_after(std::wstring const & str, wchar_t delim)
{
std::wstring::size_type pos = str.rfind(delim);
if (pos == std::wstring::npos)
{
throw 123;
}
return str.substr(pos + 1);
}
void stackoverflow()
{
std::wstring text(L"<foo>\n<bar>abc/def/ghi</bar>\n<baz>123/456/789</baz>\n</foo>\n");
std::wistringstream wiss(text);
std::wcout << text << std::endl;
std::wcout << get_substr_after(get_value(wiss, std::wstring(L"bar")), L'/') << std::endl;
}
The output of this program is:
<foo>
<bar>abc/def/ghi</bar>
<baz>123/456/789</baz>
</foo>
ghi
I hope that answered your question.
you have several issues here.
what you are getting are compiler errors and not exceptions
the header file to include is 'fstream' not 'fstream.h'.
make sure you have a line saying using namespace std;
You are declaring line as a variable of type WCHAR, so it is a single wide character, which surely is not a wstring object. Therefore line.length() is incorrect.
Why are you mixing C (wcswcs()) and C++ (STL) ? maybe you should re-design your function signature.
However, try the below function. I have modified the signature to return a pointer to WCHAR, and place the requested string in the buffer space provided by pName. I added a check to verify that the buffer is large enough to fit the name and the terminating NULL character.
WCHAR* GetSystemName(WCHAR *pName, size_t buflen)
{
wstring line;
wifstream in("image.xml");
WCHAR* tmp = NULL;
while (getline(in,line))
{
// strip whitespaces from the beginning
size_t beg_non_whitespace = line.find_first_not_of(L" \t");
if (beg_non_whitespace != wstring::npos)
{
line = line.substr( beg_non_whitespace );
}
size_t beg_system_path = line.find( L"<SystemPath>" );
if ( beg_system_path != wstring::npos )
{
// strip the tags (assuming closing tag is present)
size_t beg_data = beg_system_path + wstring( L"<SystemPath>" ).length();
size_t range = line.find( L"</SystemPath>" ) - beg_data;
line = line.substr( beg_data, range );
// get file name
size_t pos_last_backslash = line.find_last_of( L'\\' );
if ( pos_last_backslash != wstring::npos )
{
line = line.substr( pos_last_backslash + 1 );
if ( buflen <= line.length() )
{
// ERROR: pName buffer is not large enough to fit the string + terminating NULL character.
return NULL;
}
wcscpy( pName, line.c_str() );
tmp = pName;
break;
}
}
}
return tmp;
}
EDIT: Moreover, if you are using and/or parsing XML in other areas of your program, I strongly suggest using an XML parsing library such as Xerces-C or libXml2.
Thank you all for your answer. Here I got solution of my question.
PRIVATE WCHAR* GetNewSystemName()
{
WCHAR line[756];
WCHAR tempBuffer[100];
CComBSTR path = CurrentFolder.Path();
CComBSTR imagePath1 = L"rimageinfo.xml";
path.AppendBSTR(imagePath1);
std::wfstream in(path);
WCHAR tmp[756];
in.getline(line, 756);
WCHAR* buffer;
buffer = wcswcs(line, L"<SystemPath>");
WCHAR *dest = wcsstr(buffer, L"</SystemPath>");
int pos;
pos = dest - buffer;
unsigned int i = 0;
if (wcswcs(buffer,L"<SystemPath>") != NULL && wcswcs(buffer,L"</SystemPath>") != NULL)
{
for (; i < pos; i++)
{
if (buffer[i] == ' ' && sizeof(tmp) == 0)
{
}
else
{
tmp[i] = buffer[i];
}
}
tmp[i] = NULL;
//break;
}
int j = i;
for (; j > 0; j--)
{
if (tmp[j] == '\\')
{
break;
}
}
j++;
int k = 0;
for (; j < i ; j++)
{
System_Name[k] = tmp[j];
k++;
}
System_Name[k] = NULL;
return System_Name;
Suppose I have this kind of string format:
"<RGB:255,0,0>this text is colored RED.<RGB:0,255,0> While this text is colored GREEN";
I want to extract the values inside the <RGB> i.e 255,0,0 and put it on other variables then delete the chars from '<' to '>'.
My code so far:
//this function is called after the loop that checks for the existence of '<'
void RGB_ExtractAndDelete(std::string& RGBformat, int index, RGB& rgb)
{
int i = index + 5; //we are now next to character ':'
std::string value;
int toNumber;
while (RGBformat[i] != ',')
{
value += RGBformat[i++];
}
++i;
std::stringstream(value) >> toNumber;
rgb.R = toNumber;
value = "";
while (RGBformat[i] != ',')
{
value += RGBformat[i++];
}
++i;
std::stringstream(value) >> toNumber;
value = "";
rgb.G = toNumber;
while (RGBformat[i] != '>')
{
value += RGBformat[i++];
}
++i;
std::stringstream(value) >> toNumber;
value = "";
rgb.B = toNumber;
//I got the right result here which is
//start: <, end: >
printf("start: %c, end: %c\n", RGBformat[index], RGBformat[i]);
//but fail in this one
//this one should erase from '<' until it finds '>'
RGBformat.erase(index, i);
}
If I put the <RGB:?,?,?> on the start of the string, it works but it fails when it finds it next to a non '<' character. Or can you suggest much better approach how to do this?
Use std::str::find to locate the <RGB, :, , and >.
Use std::str::substr to "cut out" the string.
Add if (!std::strinstream(value)>> toNumber) ... to check that the number was actually accepted.
Something like this:
std::string::size_type index = std::RGBformat.find("<RGB");
if (index == std::string::npos)
{
... no "<RGB" found
}
std::string::size_type endAngle = std::RGBformat::find(">", index);
if (endAngle == std::string::npos)
{
... no ">" found...
}
std::string::size_type comma = std::RGBformat.find(",", index);
if (comma == std::string::npos && comma < endAngle)
{
... no "," found ...
}
std::string value = RGBformat.substr(index, comma-index-1);
std::stringstream(value) >> toNumber;
value = "";
rgb.R = toNumber;
std::string::size_type comma2 = std::RGBformat.find(",", comma+1);
if (comma2 == std::string::npos && comma2 < endAngle)
...
Note that this may look a bit clumsier than your current code, but it has the advantage of being a lot safer. If someone passed in "<RGB:55> .... " to your existing code, it would break, because it just keeps going until either you get bored and press a key to stop it, or it crashes, whichever comes first...
If you can use Boost or C++11, this is really the perfect place for regular expressions.
You can match your color specifiers with "\\<RGB:(\\d{1,3}),(\\d{1,3}),(\\d{1,3})\\>" - or if you have C++11 raw string literals, you can write this more readably as R"rx(\<RGB:(\d{1,3}),(\d{1,3}),(\d{1,3})\>)rx".
Parse it with
std::getline
http://en.cppreference.com/w/cpp/string/basic_string/getline
This function accepts a delimiter (e.g. '<' or '>') as third argument.
For an example look at:
Basic C++ program, getline()/parsing a file
Here a modified code I use to extract text from html and retrieve data from html tag when I can't use regexp. Otherwise I advice you to use regular expressions they are much more easier to setup.
In my code I ended my tags with "</>" for the color "<RGB:255,0,0>My text</>".
Hope it would help!
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
using namespace std;
typedef struct{
string text;
uint8_t r;
uint8_t g;
uint8_t b;
}TextInfo;
vector<TextInfo> vect;
const vector<TextInfo> & extractInfos(const string & str){
string newStr = str;
vect.clear();
do{
TextInfo info;
int index = newStr.find('>');
if(index != -1 && newStr.find('<') == 0){
// We get "<RGB:r,g,b>"
string color = newStr.substr(0,index+1);
// We extract red color
string red = color.substr(color.find(':') + 1, color.find(',') - color.find(':') - 1);
// We get "g,b>"
color = color.substr(color.find(',') + 1, color.length() - color.find(','));
// We extract green color
string green = color.substr(0,color.find(','));
// We extract "b>"
color = color.substr(color.find(',') + 1, color.length() - color.find('>'));
// We get blue color;
string blue = color.substr(0,color.find('>'));
// string to int into a uint8_t
info.r = atoi(red.c_str());
info.g = atoi(green.c_str());
info.b = atoi(blue.c_str());
// We remove the "<RGB:r,g,b>" part from the string
newStr = newStr.substr(index+1,newStr.length()-index);
index = newStr.find("</>");
// We get the text associated to the color just extracted
info.text = newStr.substr(0,index);
// We remove the "</>" that ends the color
newStr = newStr.substr(index+3,newStr.length()-(index+2));
}else{
// We extract the string to the next '<' or to the end if no other color is set
int i = newStr.find('<');
if(i == -1){
i=newStr.length();
}
info.text = newStr.substr(0,i);
info.r = 0;
info.g = 0;
info.b = 0; // No color then we put default to black
// We get the new part of the string without the one we just exctacted
newStr = newStr.substr(i, newStr.length() - i);
}
// We put the data into a vector
vect.push_back(info);
}while(newStr.length() != 0); // We do it while there is something to extract
return vect;
}
int main(void){
vector<TextInfo> myInfos = extractInfos("<RGB:255,0,0>String to red</><RGB:0,255,0>Green string</>Default color string");
for(vector<TextInfo>::iterator itr = myInfos.begin();itr != myInfos.end();itr++){
cout << (*itr).text << endl;
}
return 0;
}