I have been looking through the API for TinyXML and I can't find a way to check if an element exists before I try and get it by name. I have commented what I am looking for below:
#include <iostream>
#include "tinyxml.h"
int main()
{
const char* exampleText = "<test>\
<field1>Test Me</field1>\
<field2>And Me</field2>\
</test>";
TiXmlDocument exampleDoc;
exampleDoc.Parse(exampleText);
// exampleDoc.hasChildElement("field1") { // Which doesn't exist
std::string result = exampleDoc.FirstChildElement("test")
->FirstChildElement("field1")
->GetText();
// }
std::cout << "The result is: " << result << std::endl;
}
The FirstChildElement function will return a pointer, so that pointer can be used in the if-statement like so.
#include <iostream>
#include "tinyxml.h"
int main()
{
const char* exampleText = "<test>\
<field1>Test Me</field1>\
<field2>And Me</field2>\
</test>";
TiXmlDocument exampleDoc;
exampleDoc.Parse(exampleText);
TiXmlElement* field1 = exampleDoc.FirstChildElement("test")
->FirstChildElement("field1");
if (field1) {
std::string result = field1->GetText();
std::cout << "The result is: " << result << std::endl;
}
}
Related
Extraction Function
string extractStr(string str, string regExpStr) {
regex regexp(regExpStr);
smatch m;
regex_search(str, m, regexp);
string result = "";
for (string x : m)
result = result + x;
return result;
}
The Main Code
#include <iostream>
#include <regex>
using namespace std;
string extractStr(string, string);
int main(void) {
string test = "(1+1)*(n+n)";
cout << extractStr(test, "n\\+n") << endl;
cout << extractStr(test, "(\\d)\\+\\1") << endl;
cout << extractStr(test, "([a-zA-Z])[+-/*]\\1") << endl;
cout << extractStr(test, "([a-zA-Z])[+-/*]([a-zA-Z])") << endl;
return 0;
}
The Output
String = (1+1)*(n+n)
n\+n = n+n
(\d)\+\1 = 1+11
([a-zA-Z])[+-/*]\1 = n+nn
([a-zA-Z])[+-/*]([a-zA-Z]) = n+nnn
If anyone could kindly point the error I've done or point me to a similar question in SO that I've missed while searching, it would be greatly appreciated.
Regexes in C++ don't work quite like "normal" regexes. Specialy when you are looking for multiple groups later. I also have some C++ tips in here (constness and references).
#include <cassert>
#include <iostream>
#include <sstream>
#include <regex>
#include <string>
// using namespace std; don't do this!
// https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice
// pass strings by const reference
// 1. const, you promise not to change them in this function
// 2. by reference, you avoid making copies
std::string extractStr(const std::string& str, const std::string& regExpStr)
{
std::regex regexp(regExpStr);
std::smatch m;
std::ostringstream os; // streams are more efficient for building up strings
auto begin = str.cbegin();
bool comma = false;
// C++ matches regexes in parts so work you need to loop
while (std::regex_search(begin, str.end(), m, regexp))
{
if (comma) os << ", ";
os << m[0];
comma = true;
begin = m.suffix().first;
}
return os.str();
}
// small helper function to produce nicer output for your tests.
void test(const std::string& input, const std::string& regex, const std::string& expected)
{
auto output = extractStr(input, regex);
if (output == expected)
{
std::cout << "test succeeded : output = " << output << "\n";
}
else
{
std::cout << "test failed : output = " << output << ", expected : " << expected << "\n";
}
}
int main(void)
{
std::string input = "(1+1)*(n+n)";
test(input, "n\\+n", "n+n");
test(input, "(\\d)\\+\\1", "1+1");
test(input, "([a-zA-Z])[+-/*]\\1", "n+n");
return 0;
}
I would like to take the data from the struct elements to the internal elements.
What will be a better way to do it.
It shows error: invalid array assignmen berror: invalid array ssignment
error: invalid array assignment error: ‘strcpy’ was not declared in this scope.
#include <iostream>
#include <string>
using namespace std;
struct A
{
char Ip[16];
char port[6];
char sessionkey[32];
}
int main()
{
char m_ip[16];
char m_port[6];
char m_sessionkey[32];
A a;
a.Ip = "10.43.160.94111";
a.port = "12345";
a.sessionkey = "12Abcd12345Abcd12345Abcd1234512";
strcpy(m_ip,a.Ip);
strcpy(m_port,a.port);
strcpy(m_sessionkey,a.sessionkey);
cout << "m_ip:" << m_ip << endl;
cout << "m_port:" << m_port << endl;
cout << "m_sessionkey:" << m_sessionkey << endl;
}
I think you mean the following (C string functions are declared in header <cstring>)
#include <cstring>
//...
char m_ip[16];
char m_port[6];
char m_sessionkey[32];
A a = { "10.43.160.94111", "12345", "12Abcd12345Abcd12345Abcd1234512" };
std::strcpy(m_ip,a.Ip);
std::strcpy(m_port,a.port);
std::strcpy(m_sessionkey,a.sessionkey);
Or instead of
A a = { "10.43.160.94111", "12345", "12Abcd12345Abcd12345Abcd1234512" };
you could write
A a;
a = { "10.43.160.94111", "12345", "12Abcd12345Abcd12345Abcd1234512" };
provided that your compiler supports C++ 2011.
Take into account that you forgot to place a semicol after the closing brace in the structure definition
struct A
{
//...
};
^^^
EDIT: After you unexpectedly changed your code I'd like to point out that this code snippet
A a;
string p = "10.43.160.94111";
string q = "12345";
string r = "12Abcd12345Abcd12345Abcd1234512";
p.copy(a.Ip,16,0);
q.copy(a.port,6,0);
r.copy(a.sessionkey,32,0);
does not make sense. There is no sense to introduce objects of type std::string only that to initialize an object of type struct A.
Another thing you could initially define the structure the following way
struct A
{
std::string Ip;
std::string port;
std::string sessionkey;
};
For writing in C++ prefer to use std::string instead of char * or char[].
A number of your issues will not longer exist if you use std::string instead.
Example:
#include <iostream>
#include <string>
struct A
{
std::string Ip;
std::string port;
std::string sessionkey;
};
int main()
{
std::string m_ip;
std::string m_port;
std::string m_sessionkey;
A a;
a.Ip = "10.43.160.94111";
a.port = "12345";
a.sessionkey = "12Abcd12345Abcd12345Abcd1234512";
// copy data from a to local variables
m_ip = a.Ip;
m_port = a.port;
m_sessionkey = a.sessionkey;
std::cout << "m_ip:" << m_ip << std::endl;
std::cout << "m_port:" << m_port << std::endl;
std::cout << "m_sessionkey:" << m_sessionkey << std::endl;
}
If you insist on using strcpy you must include the C header file string.h either by using #include <string.h> or by using #include <cstring>. Note that this is a C header file and it is distinctly different than the C++ #include <string> header file.
You should change your code like this:
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
struct A
{
char* Ip;
char* port;
char* sessionkey;
};
int main()
{
char m_ip[16];
char m_port[6];
char m_sessionkey[32];
A a;
a.Ip = "10.43.160.94111";
a.port = "12345";
a.sessionkey = "12Abcd12345Abcd12345Abcd1234512";
strcpy(m_ip,a.Ip);
strcpy(m_port,a.port);
strcpy(m_sessionkey,a.sessionkey);
cout << "m_ip:" << m_ip << endl;
cout << "m_port:" << m_port << endl;
cout << "m_sessionkey:" << m_sessionkey << endl;
}
strcpy() function is in cstring header file in C++/C++11, so you must add #include<cstring> to your code.
I have a text file that has #'s in it...It looks something like this.
#Stuff
1
2
3
#MoreStuff
a
b
c
I am trying to use std::string::find() function to get the positions of the # and then go from there, but I'm not sure how to actually code this.
This is my attempt:
int pos1=0;
while(i<string.size()){
int next=string.find('#', pos1);
i++;}
Here's one i made a while ago... (in C)
int char_pos(char c, char *str) {
char *pch=strchr(str,c);
return (pch-str)+1;
}
Port it to C++ and there you go! ;)
If : Not Found Then returns Negative.
Else : Return 'Positive', Char's 1st found position (1st match)
It's hard to tell from your question what you mean by "position", but it looks like you are trying to do something like this:
#include <fstream>
#include <iostream>
int main()
{
std::ifstream incoming{"string-parsing-for-c.txt"};
std::string const hash{"#"};
std::string line;
for (auto line_number = 0U; std::getline(incoming, line); ++line_number)
{
auto const column = line.find(hash);
if (std::string::npos != column)
{
std::cout << hash << " found on line " << line_number
<< " in column " << column << ".\n";
}
}
}
...or possibly this:
#include <fstream>
#include <iostream>
int main()
{
std::ifstream incoming{"string-parsing-for-c.txt"};
char const hash{'#'};
char byte{};
for (auto offset = 0U; incoming.read(&byte, 1); ++offset)
{
if (hash == byte)
{
std::cout << hash << " found at offset " << offset << ".\n";
}
}
}
lexical_cast throws an exception in the following case. Is there a way to use lexical_cast and convert the string to integer.
#include <iostream>
#include "boost/lexical_cast.hpp"
#include <string>
int main()
{
std::string src = "124is";
int iNumber = boost::lexical_cast<int>(src);
std::cout << "After conversion " << iNumber << std::endl;
}
I understand, I can use atoi instead of boost::lexical_cast.
If I'm understanding your requirements correctly it seems as though removing the non-numeric elements from the string first before the lexical_cast will solve your problem. The approach I outline here makes use of the isdigit function which will return true if the given char is a digit from 0 to 9.
#include <iostream>
#include "boost/lexical_cast.hpp"
#include <string>
#include <algorithm>
#include <cctype> //for isdigit
struct is_not_digit{
bool operator()(char a) { return !isdigit(a); }
};
int main()
{
std::string src = "124is";
src.erase(std::remove_if(src.begin(),src.end(),is_not_digit()),src.end());
int iNumber = boost::lexical_cast<int>(src);
std::cout << "After conversion " << iNumber << std::endl;
}
The boost/lexical_cast uses stringstream to convert from string to other types,so you must make sure the string can be converted completely! or, it will throw the bad_lexical_cast exception,This is an example:
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>
#define ERROR_LEXICAL_CAST 1
int main()
{
using boost::lexical_cast;
int a = 0;
double b = 0.0;
std::string s = "";
int e = 0;
try
{
// ----- string --> int
a = lexical_cast<int>("123");//good
b = lexical_cast<double>("123.12");//good
// -----double to string good
s = lexical_cast<std::string>("123456.7");
// ----- bad
e = lexical_cast<int>("abc");
}
catch(boost::bad_lexical_cast& e)
{
// bad lexical cast: source type value could not be interpreted as target
std::cout << e.what() << std::endl;
return ERROR_LEXICAL_CAST;
}
std::cout << a << std::endl; // cout:123
std::cout << b << std::endl; //cout:123.12
std::cout << s << std::endl; //cout:123456.7
return 0;
}
I would like to pass the variable from a function to the main scope which I'm calling, I'm trying to do like I use to do in C but it returns nothing.
I want to be able to output and deal with it after the return of the function
#include "StdAfx.h"
#include <regex>
#include <iostream>
#include <string>
#include <conio.h>
using namespace std;
std::tr1::match_results<std::string::const_iterator> match(std::string& regex, const std::string& ip,std::tr1::match_results<std::string::const_iterator> res)
{
const std::tr1::regex pattern(regex.c_str());
bool valid = std::tr1::regex_match(ip, res, pattern);
std::cout << ip << " \t: " << (valid ? "valid" : "invalid") << std::endl;
cout << "FIRST RES FOUND: " << res[1] << endl;
return res;
}
int main()
{
string regex = "(\\d{1,3}):(\\d{1,3}):(\\d{1,3}):(\\d{1,3})";
string ip = "49:22:33:444";
std::tr1::match_results<std::string::const_iterator> res;
match(regex,ip.c_str(), res);
cout << "Result >" << res[1] << "< " << endl;
_getch(); return 0;
}
When I compile and run, The output is: "FIRST RES FOUND: 49
Result ><"
It's probably a really simple solution but what do I have to do to set it for my main can read it correctly as in: "Result >49<"
Thanks in advance. :)
Option 1: Use references:
void match(string& regex, const string& ip, tr1::match_results<string::const_iterator> & res)
{
const tr1::regex pattern(regex.c_str());
bool valid = tr1::regex_match(ip, res, pattern);
cout << ip << " \t: " << (valid ? "valid" : "invalid") << endl;
cout << "FIRST RES FOUND: " << res[1] << endl;
}
Option 2: Return the result by value and store it:
tr1::match_results<string::const_iterator> match(string& regex, const string& ip)
{
tr1::match_results<string::const_iterator> res;
// ...
return res;
}
int main()
{
// ...
tr1::match_results<string::const_iterator> res = match(regex, ip);
}
On a separate note, there should be absolutely no need for all the c_str() calls, as <regex> has a perfectly functional std::string interface. Check the documentation for details, you just have to get a couple of typenames right.
Edit: Here are some basic examples on using std::string. There are equivalent constructions for std::wstring, char* and wchar_t*, but std::strings should be the most useful one.
Since <regex> support is still patchy, you should consider the TR1 and Boost alternatives, too; I provide all three and you can pick one:
namespace ns = std; // for <regex>
namespace ns = std::tr1; // for <tr1/regex>
namespace ns = boost; // for <boost/regex.hpp>
ns::regex r("");
ns::smatch rxres; // 's' for 'string'
std::string data = argv[1]; // the data to be matched
// Fun #1: Search once
if (!ns::regex_search(data, rxres, r))
{
std::cout << "No match." << std::endl;
return 0;
}
// Fun #2: Iterate over all matches
ns::sregex_iterator rt(data.begin(), data.end(), r), rend;
for ( ; rt != rend; ++rt)
{
// *rt is the entire match object
for (auto it = rt->begin(), end = rt->end(); it != end; ++it)
{
// *it is the current capture group; the first one is the entire match
std::cout << " Match[" << std::distance(rt->begin(), it) << "]: " << *it << ", length " << it->length() << std::endl;
}
}
Don't forget to handle exceptions of type ns::regex_error.
Pass in res by reference instead of by value. In other words, declare the parameter res as a reference instead of a value, i.e., type &res, not type res.