i have this simple code:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string s = "1,0";
string result;
//result.resize(s.length());
replace_copy(s.begin(), s.end(), result.begin(), ',', '.');
cout << '"' << result << '"' << endl;
cout << '"' << result.c_str() << '"' << endl;
cout << result.length() << endl;
return 0;
}
Console output of this program with result.resize line uncommented is:
"1.0"
"1.0"
3
-thats Ok, but when line with result.resize is commented-out, output is :
""
"1.0"
0
-this can leads into weird errors because result != result.c_str() !!!
Can this behavior of replace_copy (and posibly also similar templates) may be considered as error in standard library? I cannot find anything relevant to this subject. Thanks.
Compiler: mingw32-g++ 4.7.1
What did you expect?
Without the resize, there is no space in your string for the new characters.
Trying to copy into that space regardless will definitely result in "weird" [read: undefined] behaviour. You're mangling your memory.
replace_copy copies to a target range, which is not the same as inserting new elements into a target container. The range has to already exist…
… unless you use a back_inserter, which functions as a sort of fake range, that actually performs insertion under the hood:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string s = "1,0";
string result;
//result.resize(s.length()); // Look, ma! No hands!
replace_copy(
s.begin(), s.end(),
std::back_inserter<std::string>(result),
',', '.'
);
cout << '"' << result << '"' << endl;
cout << '"' << result.c_str() << '"' << endl;
cout << result.length() << endl;
}
// "1.0"
// "1.0"
// 3
Live demo
Warning! Getting the right output in that live demo does not prove anything, as undefined behaviour can occasionally "appear to work". However, I have 96k rep and you can trust me. ;)
When you used statement
result.resize(s.length());
you created and initialized (more precisely assigned) the string with three elements with values '\0'. When this statement was not used the string had no relements and the behaviour of the program was undefined.In fact the code with uncommented line is equivalent to the following:
string s = "1,0";
string result( s.length(), '\0' );
replace_copy(s.begin(), s.end(), result.begin(), ',', '.');
If to write as it was with the commented statement then you should use iterator adapter std::back_insert_iteratorFor example
replace_copy(s.begin(), s.end(), std::back_inserter( result ), ',', '.');
Related
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)))
This question already has answers here:
Is gcc 4.8 or earlier buggy about regular expressions?
(3 answers)
Closed 6 years ago.
I am trying to do regex_match on a string which have square brackets([...]) inside it.
Things I have tried so far:
Normal matching
Backslashing the square brackets with 1 slash
Backslashing the square brackets with 2 slashes
Code to repro:
#include <iostream>
#include <cstring>
#include <regex>
using namespace std;
int main () {
std::string str1 = "a/b/c[2]/d";
std::string str2 = "(.*)a/b/c[2]/d(.*)";
std::regex e(str2);
std::cout << "str1 = " << str1 << std::endl;
std::cout << "str2 = " << str2 << std::endl;
if (regex_match(str1, e)) {
std::cout << "matched" << std::endl;
}
}
This is the error message I get every time I compile it.
terminate called after throwing an instance of 'std::regex_error'
what(): regex_error
Aborted (core dumped)
I was told by stack overflow members that gcc 4.8 or earlier version of it are known to be buggy. So, I needed to update it to latest version.
I have created an Ideone fiddle where compiler should not be issue. Even there, I do not see regex_match happening.
The main problem you have is the outdated gcc compiler: you need to upgrade to some recent version. 4.8.x just does not support regex as it should.
Now, the code you should be using is:
#include <iostream>
#include <cstring>
#include <regex>
using namespace std;
int main () {
std::string str1 = "a/b/c[2]/d";
std::string str2 = R"(a/b/c\[2]/d)";
std::regex e(str2);
std::cout << "str1 = " << str1 << std::endl;
std::cout << "str2 = " << str2 << std::endl;
if (regex_search(str1, e)) {
std::cout << "matched" << std::endl;
}
}
See the IDEONE demo
Use
regex_search instead of regex_match to search for partial matches (regex_match requires a full string match)
The [2] in the regex pattern matches a literal 2 ([...] is a character class matching 1 character from the range/list specified in the character class). To match the literal square brackets, you need to escape the [ and you do not have to escape ]: R"(a/b/c\[2]/d)".
Well they should definitely be escaped by using a backslash. Unfortunately since backslash is itself special in a literal string you need two backslashes. So the regex should look like "(.*)a/b/c\\[2\\]/d(.*)".
Raw string literals often simplify cases where one would otherwise have to have complex escape sequences:
#include <iostream>
#include <cstring>
#include <regex>
using namespace std;
int main () {
std::string str1 = "a/b/c[2]/d";
std::string str2 = R"regex((.*)a/b/c[2]/d(.*))regex";
std::regex e(str2);
std::cout << "str1 = " << str1 << std::endl;
std::cout << "str2 = " << str2 << std::endl;
if (regex_match(str1, e)) {
std::cout << "matched" << std::endl;
}
}
expected output:
str1 = a/b/c[2]/d
str2 = (.*)a/b/c[2]/d(.*)
I have the following function, which writes a vector to a CSV file:
#include <math.h>
#include <vector>
#include <string>
#include <fstream>
#include <iostream>
#include <iterator>
using namespace std;
bool save_vector(vector<double>* pdata, size_t length,
const string& file_path)
{
ofstream os(file_path.c_str(), ios::binary | ios::out);
if (!os.is_open())
{
cout << "Failure!" << endl;
return false;
}
os.precision(11);
copy(pdata->begin(), pdata->end(), ostream_iterator<double>(os, ","));
os.close();
return true;
}
However, the end of the CSV file looks like this:
1.2000414752e-08,1.1040914566e-08,1.0158131779e-08,9.3459324063e-09,
That is, a trailing comma is written into the file. This is causing an error when I attempt to load the file using another software program.
What is the easiest, most efficient way to get rid of (ideally, never write) this trailing comma?
As you observed, copying via std::copy doesn't do the trick, one additional , is output. There is a proposal that will probably make it in the future C++17 standard: ostream_joiner, which will do exactly what you expect.
However, a quick solution available now is to do it manually.
for(auto it = std::begin(*pdata); it != std::end(*pdata); ++it)
{
if (it != std::begin(*pdata))
std::cout << ",";
std::cout << *it;
}
I'd omit printing the comma by treating the first element special:
if (!pdata->empty()) {
os << pdata->front();
std::for_each(std::next(pdata->begin()), pdata->end(),
[&os](auto&& v){ os << ", " << v; });
}
Obviously, this code goes into a function printing a printable range adapter.
There are many ways, besides already listed:
std::string sep;
for (const auto& x : *pdata) {
os << x << clusAvg;
sep = ", ";
}
or
auto it = pdata->begin();
if (it != pdata->end()) {
os << *it;
for(; it != pdata->end(); ++it)
os << ", " << *it;
}
or
auto it = pdata->end();
if (it != pdata->begin()) {
--it;
std::copy(pdata->begin(), it, ostream_iterator<double>(os, ", "));
os << *it;
}
I have a string of the form:
http://stackoverflow.com/q""uestions/ask/%33854#/á
Now I want to delete all characters from this string except alphnumeric and ://.So that the output string becomes:
http://stackoverflow.com/questions/ask/33854/á
I know I can traverse this string character by character and remove unnecessary characters. But is there some function in some standard library which may help me remove unwanted characters. If i know the unwanted characters then I can use std::remove and std::replace to selectively remove or replace. But here I do not know the unknown characters, I only know the characters which I want to retain.
Is there some way by which I may retain only the necessary characters and remove the unwanted characters.
gcc version which I am using is:
gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4)
EDIT: I also want to include characters like á. I dont know what they are called. I know they are not alph-numeric. But I am not getting how to check for them
Since your compiler is ancient and regex support is relatively recent in gcc (from gcc 4.9 forward), regexes are not an option. We'll use the erase-remove idiom, with a named function because Gcc 4.4 does not yet support lambdas.
#include <algorithm>
#include <iostream>
#include <locale>
#include <string>
// true for characters that should be removed
bool is_special_character(char c) {
std::locale loc("your_locale_string_here");
return !std::isalnum(c, loc) && c != ':' && c != '/' && c != '.';
}
int main()
{
std::string s = "http://stackoverflow.com/q\"\"uestions/ask/%33854#";
// interesting part here
s.erase(std::remove_if(s.begin(), s.end(), is_special_character), s.end());
std::cout << s << '\n';
}
You will want to use std::remove_if and define a predicate to return false only if the characters are the ones you want to retain.
You'll also want to resize the string to the new length after you do this process. As an example:
#include <string>
#include <algorithm>
#include <iostream>
#include <locale>
bool is_special_char(char c)
{
return !( std::isalnum(c) || c == ':' || c == '/' || c == '.');
}
int main()
{
std::string s = "http://stackoverflow.com/q\"\"uestions/ask/\%33854#";
std::cout << s << std::endl;
std::string::iterator new_end = std::remove_if(s.begin(), s.end(), is_special_char);
s.resize(new_end - s.begin());
std::cout << s << std::endl;
}
will output
http://stackoverflow.com/q""uestions/ask/%33854#
http://stackoverflow.com/questions/ask/33854
If you want to incorporate unicode characters you need to use a wstring instead of a string, an example using this (and incorporating Wintermute's nice use of the erase/remove idiom) would be.
#include <string>
#include <algorithm>
#include <iostream>
#include <locale>
bool is_special_char(wchar_t c)
{
return !( std::iswalnum(c) || c == ':' || c == '/' || c == '.');
}
int main()
{
std::locale::global( std::locale("en_US.UTF-8") ); //Set the global locale to Unicode
std::wstring s = L"http://stáckoverflow.com/q\"\"uestions/ask/%33854#";
std::wcout << s << std::endl;
s.erase( std::remove_if(s.begin(), s.end(), is_special_char), s.end() );
std::wcout << s << std::endl;
}
which will output
http://stáckoverflow.com/q""uestions/ask/%33854#
http://stáckoverflow.com/questions/ask/33854
But here I do not know the unknown characters, I only know the characters which I want to retain.
Whitelist the characters you want to retain using a char array for example. Then run through each character in your string and remove it if it isn't in the whitelist.
You could try something like that :
std::string str ("This is an example sentence.");
std::cout << str << '\n';
// "This is an example sentence."
str.erase (10,8); // ^^^^^^^^
std::cout << str << '\n';
// "This is an sentence."
str.erase (str.begin()+9); // ^
std::cout << str << '\n';
// "This is a sentence."
str.erase (str.begin()+5, str.end()-9); // ^^^^^
std::cout << str << '\n';
// "This sentence."
This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
Don't print space after last number
Printing lists with commas C++
#include <vector>
#include <iostream>
#include <sstream>
#include <boost/foreach.hpp>
using namespace std;
int main()
{
vector<int> VecInts;
VecInts.push_back(1);
VecInts.push_back(2);
VecInts.push_back(3);
VecInts.push_back(4);
VecInts.push_back(5);
stringstream ss;
BOOST_FOREACH(int i, VecInts)
{
ss << i << ",";
}
cout << ss.str();
return 0;
}
This prints out: 1,2,3,4,5,
However I want: 1,2,3,4,5
How can I achieve that in an elegant way?
I see there is some confusion about what I mean with "elegant": E.g. no slowing down "if-clause" in my loop. Imagine 100.000 entries in the vector! If that is all you have to offer, I'd rather remove the last comma after I have gone through the loop.
How about this:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <string>
#include <sstream>
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
std::ostringstream ss;
if(!v.empty()) {
std::copy(v.begin(), std::prev(v.end()), std::ostream_iterator<int>(ss, ", "));
ss << v.back();
}
std::cout << ss.str() << "\n";
}
No need to add extra variables and doesn't even depend on boost! Actually, in addition to the "no additional variable in the loop" requirement, one could say that there is not even a loop :)
Detecting the one before last is always tricky, detecting the first is very easy.
bool first = true;
stringstream ss;
BOOST_FOREACH(int i, VecInts)
{
if (!first) { ss << ","; }
first = false;
ss << i;
}
Using Karma from Boost Spirit - has a reputation for being fast.
#include <iostream>
#include <vector>
#include <boost/spirit/include/karma.hpp>
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
using namespace boost::spirit::karma;
std::cout << format(int_ % ',', v) << std::endl;
}
Try:
if (ss.tellp ())
{
ss << ",";
}
ss << i;
Alternatively, if the "if" is making you worried:
char *comma = "";
BOOST_FOREACH(int i, VecInts)
{
ss << comma << i;
comma = ",";
}
Personally, I like a solution that does not cause potential memory allocations (because the string grows larger than needed). An extra-if within the loop body should be tractable thanks to branch target buffering, but I would do so:
#include <vector>
#include <iostream>
int main () {
using std::cout;
typedef std::vector<int>::iterator iterator;
std::vector<int> ints;
ints.push_back(5);
ints.push_back(1);
ints.push_back(4);
ints.push_back(2);
ints.push_back(3);
if (!ints.empty()) {
iterator it = ints.begin();
const iterator end = ints.end();
cout << *it;
for (++it; it!=end; ++it) {
cout << ", " << *it;
}
cout << std::endl;
}
}
Alternatively, BYORA (bring your own re-usable algorithm):
// Follow the signature of std::getline. Allows us to stay completely
// type agnostic.
template <typename Stream, typename Iter, typename Infix>
inline Stream& infix (Stream &os, Iter from, Iter to, Infix infix_) {
if (from == to) return os;
os << *from;
for (++from; from!=to; ++from) {
os << infix_ << *from;
}
return os;
}
template <typename Stream, typename Iter>
inline Stream& comma_seperated (Stream &os, Iter from, Iter to) {
return infix (os, from, to, ", ");
}
so that
...
comma_seperated(cout, ints.begin(), ints.end()) << std::endl;
infix(cout, ints.begin(), ints.end(), "-") << std::endl;
infix(cout, ints.begin(), ints.end(), "> <") << std::endl;
...
output:
5, 1, 4, 2, 3
5-1-4-2-3
5> <1> <4> <2> <3
The neat thing is it works for every output stream, any container that has forward iterators, with any infix, and with any infix type (interesting e.g. when you use wide strings).
I like moving the test outside the loop.
It only needs to be done once. So do it first.
Like this:
if (!VecInts.empty())
{
ss << VecInts[0]
for(any loop = ++(VecInts.begin()); loop != VecInts.end(); ++loop)
{
ss << "," << *loop;
}
}
You can either trim the string at the end, or using single for loop instead of foreach and dont concatenate at the last iteration
Well, if you format into a stringstream anyway, you can just trim the resulting string by one character:
cout << ss.str().substr(0, ss.str().size() - 1);
If the string is empty, than the second argument says -1, which means everything and does not crash and if the string is non-empty, it always ends with a comma.
But if you write to an output stream directly, I never found anything better than the first flag.
That is unless you want to use join from boost.string algo.
This would work
stringstream ss;
BOOST_FOREACH(int const& i, VecInts)
{
if(&i != &VecInts[0])
ss << ", ";
ss << i;
}
I suspect with "elegant" you mean "without introducing a new variable". But I think I would just do it "non-elegant" if I couldn't find anything else. It's still clear
stringstream ss;
bool comma = false;
BOOST_FOREACH(int i, VecInts)
{
if(comma)
ss << ", ";
ss << i;
comma = true;
}
Imagine 100.000 entries in the vector! If that is all you have to offer, I'd rather remove the last comma after I have gone thorough the loop.
You are saying that as if printing ss << i is one machine instruction. Come on, executing that expression will execute lots of if's and loops inside. Your if will be nothing compared to that.
cout << ss.str()<<"\b" <<" ";
You can add the "\b" backspace
This will overwrite the extra "," .
for Example :
int main()
{
cout<<"Hi";
cout<<'\b'; //Cursor moves 1 position backwards
cout<<" "; //Overwrites letter 'i' with space
}
So the output would be
H