I wanted to know if there is any efficient method of getting a string as input and then performing some operation on its characters individually?
Also, after performing operations (check that length of string may also increase or decrease), can we output the new string (string got after performing operations) instead of outputting the characters individually using a for loop?
Note that time is a crucial factor, please provide fastest methods.
Is there is any efficient method of getting a string as input and then performing some operation on its characters individually?
Yes, there is: read std::string as usual (say, with std::getline or the >> operator of an input stream), and then access the individual characters in a loop.
std::string str;
std::getline(std::cin, str);
for (int i = 0 ; i != str.size() ; i++) {
std::cout << "Code of character " << i << " is " << (int)str[i] << std::endl;
}
First demo on ideone.
Also, after performing operations, can we output the new string (string got after performing operations) instead of outputting the characters individually using a for loop?
Yes, you can: std::string is mutable, meaning that you can change it in place.
std::string str;
std::getline(std::cin, str);
for (int i = 0 ; i != str.size() ; i++) {
if (!std::isalpha(str[i])) {
str[i] = '#';
}
}
std::cout << str << std::endl;
Second demo on ideone.
You can do it like this:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string in;
cout << "Input please\n";
cin >> in;
if(in.size() >= 5)
in[5] = 'A';
cout << in << "\n";
return 0;
}
Or you can use std::getline(), instead of std::cin.
Output:
Input please
samaras
samarAs
However, are you sure this is the bottleneck of your program? You can check this with some profiling tools, like the one I use.
[EDIT]
Since OP is asking about efficiency, I did some testing. However, you can to take into account the time that user takes to type the input, but since I am the same person, we can assume this is constant.
So, I did modified a bit a code from another answer, like this:
std::string str;
cout << "Input please\n";
std::getline(std::cin, str);
if (str.size() >= 5) {
str[5] = '#';
}
std::cout << str << "\n";
Output:
Input please
Samaras
Samar#s
It took me 1.04237 seconds.
And with my code, I got
Input please
Samaras
SamarAs
It took me 0.911217 seconds.
Which actually show that they are pretty close and I would say the difference is due to my typing speed.
I did the timings with std::chrono, like the code I have in my pseudo-site.
Basic operation... Some search on the internet could have helped you but here you go...
std::string processStr(const std::string &str)
{
for (std::string::iterator it = str.begin(); it != str.end(); ++it)
// process your string (getting a char is done by dereferencing the iterator
// like this: *it
return (str);
}
Related
i am trying to get my file to remove the leading and trailing space but it does not work.
this is the txt file contents:
392402 wench
I have tried printing out my code, and this is what is displayed.
first: 392402 wench second:
I want it to display this instead
first: 392402 second: wench
this is my code
void readFile(const string &fileName) {
int limit;
ifstream ifs(fileName);
string::size_type position;
key_type item;
mapped_type count;
string line;
if (ifs.is_open()) {
ifs >> limit;
for (int i = 0; i < limit; i++) {
getline(ifs, line);
position = line.find(" ", 0);
auto c = line.substr(position + 1);
item = line.substr(0, position);
cout << "first: " << c << " second: " << item << endl;
value_type value(item, count);
values.push_back(value);
}
} else {
cout << "Can't open file.";
}
what am i doing wrong? Thank you
The two biggest mistakes you're making are (a) not checking your values for expected output as you go, and (b) not running your code in a debugger to see what is really happening. If you had, the values of position, c, and item would have been blatantly wrong, and you could then surmise where to go from there.
Belaying the highly-likely possibility that the loop iteration is broken from inception because you never consumed the remainder of the entry line containing input, let's look at the actual data and what you're asking of it with your code.
We read this entire line:
392402 wench
You then ask "find the first single-space string in this line" via this code:
position = line.find(" ", 0);
Well, that would be here:
392402 wench
^here
So position is zero (0). You then ask for the sub-string, starting a that position + 1, through the end of the string with this code:
auto c = line.substr(position + 1);
Therefore c now contains (leading space removed via the +1):
392402 wench
Now we build item, which is done with this line:
item = line.substr(0, position);
Remember, position is zero, so you're asking for the string, starting at location 0, length 0. As you can imagine, that isn't going to amount to anything. So now item is an empty string.
Finally, the output statement:
cout << "first: " << c << " second: " << item << endl;
will produce:
first: 392402 wench second:
I.e. exactly what you're seeing. And that's it. Clearly this is wrong.
Alternative
Use better error checking, value checking, and a string stream for per-line extraction. The following code doesn't give two cents about your type aliases (mainly because you didn't include them anyway and I'd rather not loft any guesses as to their origin).
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <limits>
// Expects a file with the following format:
// count
// name1 value1
// name2 value2
// ...
void readFile(const std::string &fileName)
{
std::ifstream ifs(fileName);
if (ifs.is_open())
{
int limit;
if (ifs >> limit && limit > 0)
{
// consume through end of line.
ifs.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// repeat until `limit` iterations or stream error/eof
std::string line;
for (int i = 0; i < limit && std::getline(ifs, line); i++)
{
std::istringstream iss(line);
// extract line values. Note these *can* be formatted
// extraction for things besides just strings
std::string first, second;
if (iss >> first >> second)
{
std::cout << "first: " << first << " second: " << second << '\n';
// TODO: whatever you want to do with first/second
}
}
}
ifs.close();
}
else
{
std::cerr << "Can't open file: " << fileName << '\n';
}
}
Note: The above code will NOT work for remaining-line-content as the expected second value. E.g. It will not process something like this as you may first expect:
10000 this is a multi-word description
will produce this:
first: 10000 second: this
which is considerably different than what you may be expecting:
first: 10000 second: this is a multi-word description
There was no suggestion in the original post such support was mandatory, though adding it wouldn't be terribly difficult to add. If it is a requirement, I leave that task to you.
I've tried a bunch of methods listed on here but none of them work. It's always waiting for more input.
I've tried while(std::getline(std::cin, line)) and the method below, nothing seems to work:
#include <iostream>
#include <sstream>
using namespace std;
int main(){
long length = 1UL<<32;
int array[length];
// memset(array, 0, (length-1) * sizeof(int));
for(int i = 0; i < length; i++)
array[i] = 0;
string line;
int num;
while(!cin.eof()){
getline(cin,line);
stringstream ss(line);
ss >>num;
array[num]++;
}
for(int i = 0; i < length; i++)
if(array[i]){
cout << i << ": ";
cout << array[i] << endl;
}
}
First off, do not use std::cin.eof() to control your loop! It doesn't work. Also, you always need to check for successful input after the input.
That said, to terminate the input you'll need to enter the appropriate end of file character, probably at the start of the line (how it works entirely somewhat depends on the system, some settings, etc.). On Windows you'd use Ctrl-Z, on UNIXes you'd use Ctrl-D.
First off, this part of your program attempts to allocate 4 GB of memory on the stack, which doesn't work on my machine (good luck finding any machine with 4 GB of continuous memory space):
long length = 1UL<<32;
int array[length];
If I change that to a much more reasonable:
long length = 32;
Then it works fine for me:
$ g++ -g test.cpp -o test && ./test
2
5
# pressed control+d
2: 1
5: 2
$
So I'm guessing something else is wrong.
Note: Unless you actually plan to use all of those indexes, you may want to considering using an unordered_map, so you only use the space you actually need.
The condition you are looking for can be most easily tested by evaluating "std::cin" as a bool, i.e. while (cin). But it won't do this until you have tried to read beyond EOF, so expect an empty getline:
#include <iostream>
#include <string>
int main() {
std::string input;
while (std::cin) {
std::cout << "Type something in:\n";
std::getline(std::cin, input);
if(input.empty())
continue;
std::cout << "You typed [" << input << "]\n";
}
std::cout << "Our work here is done.\n";
return 0;
}
Live demo: http://ideone.com/QR9fpM
I am trying to learn C++ since yesterday and I am using this document: http://www.cplusplus.com/files/tutorial.pdf (page 32). I found a code in the document and I ran it. I tried inputting Rs 5.5 for price and an integer for quantity and the output was 0.
I tried inputting 5.5 and 6 and the output was correct.
// stringstreams
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main ()
{
string mystr;
float price = 0;
int quantity = 0;
cout << "Enter price: ";
getline (cin,mystr);
stringstream(mystr) >> price;
cout << "Enter quantity: ";
getline (cin,mystr);
stringstream(mystr) >> quantity;
cout << "Total price: " << price*quantity << endl;
return 0;
}
What exactly does the mystring command do? Quoting from the document:
"In this example, we acquire numeric values from the standard input
indirectly. Instead of extracting numeric values directly from the
standard input, we get lines from the standard input (cin) into a
string object (mystr), and then we extract the integer values from
this string into a variable of type int (quantity)."
My impression was that the function will take an integral part of a string and use that as input.
Sometimes it is very convenient to use stringstream to convert between strings and other numerical types. The usage of stringstream is similar to the usage of iostream, so it is not a burden to learn.
Stringstreams can be used to both read strings and write data into strings. It mainly functions with a string buffer, but without a real I/O channel.
The basic member functions of stringstream class are
str(), which returns the contents of its buffer in string type.
str(string), which set the contents of the buffer to the string argument.
Here is an example of how to use string streams.
ostringstream os;
os << "dec: " << 15 << " hex: " << std::hex << 15 << endl;
cout << os.str() << endl;
The result is dec: 15 hex: f.
istringstream is of more or less the same usage.
To summarize, stringstream is a convenient way to manipulate strings like an independent I/O device.
FYI, the inheritance relationships between the classes are:
From C++ Primer:
The istringstream type reads a string, ostringstream writes a string, and stringstream reads and writes the string.
I come across some cases where it is both convenient and concise to use stringstream.
case 1
It is from one of the solutions for this leetcode problem. It demonstrates a very suitable case where the use of stringstream is efficient and concise.
Suppose a and b are complex numbers expressed in string format, we want to get the result of multiplication of a and b also in string format. The code is as follows:
string a = "1+2i", b = "1+3i";
istringstream sa(a), sb(b);
ostringstream out;
int ra, ia, rb, ib;
char buff;
// only read integer values to get the real and imaginary part of
// of the original complex number
sa >> ra >> buff >> ia >> buff;
sb >> rb >> buff >> ib >> buff;
out << ra*rb-ia*ib << '+' << ra*ib+ia*rb << 'i';
// final result in string format
string result = out.str()
case 2
It is also from a leetcode problem that requires you to simplify the given path string, one of the solutions using stringstream is the most elegant that I have seen:
string simplifyPath(string path) {
string res, tmp;
vector<string> stk;
stringstream ss(path);
while(getline(ss,tmp,'/')) {
if (tmp == "" or tmp == ".") continue;
if (tmp == ".." and !stk.empty()) stk.pop_back();
else if (tmp != "..") stk.push_back(tmp);
}
for(auto str : stk) res += "/"+str;
return res.empty() ? "/" : res;
}
Without the use of stringstream, it would be difficult to write such concise code.
To answer the question. stringstream basically allows you to treat a string object like a stream, and use all stream functions and operators on it.
I saw it used mainly for the formatted output/input goodness.
One good example would be c++ implementation of converting number to stream object.
Possible example:
template <class T>
string num2str(const T& num, unsigned int prec = 12) {
string ret;
stringstream ss;
ios_base::fmtflags ff = ss.flags();
ff |= ios_base::floatfield;
ff |= ios_base::fixed;
ss.flags(ff);
ss.precision(prec);
ss << num;
ret = ss.str();
return ret;
};
Maybe it's a bit complicated but it is quite complex. You create stringstream object ss, modify its flags, put a number into it with operator<<, and extract it via str(). I guess that operator>> could be used.
Also in this example the string buffer is hidden and not used explicitly. But it would be too long of a post to write about every possible aspect and use-case.
Note: I probably stole it from someone on SO and refined, but I don't have original author noted.
You entered an alphanumeric and int, blank delimited in mystr.
You then tried to convert the first token (blank delimited) into an int.
The first token was RS which failed to convert to int, leaving a zero for myprice, and we all know what zero times anything yields.
When you only entered int values the second time, everything worked as you expected.
It was the spurious RS that caused your code to fail.
I am making a statistics collector that reads the log of a music player and lets the user show top ten most played etc. As a noob project.
A line from the log looks like: "20:42:03 start E:\ROTATION\A\HÃ¥kan Lidbo - Dammlunga.mp3"
I have put this in a string using ifstream and getline.
Then making an array of chars of the string using
const char *charveqtur = newline.c_str();
Then I tried to sort i out with sscanf:
sscanf (charveqtur, "%d:%d:%d\tstart\t%s", &this->hour, &this->minute, &this->second, &this->filename);
The problem is that the filename is cut at the first space. I have also tried using istringstream instead but no breakthrough so far.
Which is the most convinient way of doing this? Thanks.
You can use some input stream to read the first integers and colons, and because the filename is the last entity, you can then use std::getline. However, even if your filename is not the last part, note that std::getline is quite a versatile function that accepts any delimiter.
A more advanced method would be to define your own type for filenames and overload operator>>(std::istream &, T const &) on it.
Here is a complete example using std::getline and stringstream with basic diagnostics and some reformatting:
#include <sstream> // for istringstream
#include <iostream> // for cout and cerr
#include <iomanip> // for setprecision
#include <cmath>
bool read (std::string const &line) {
char c = 0;
double length;
double rating;
std::string title;
std::istringstream ss;
ss.str (line);
ss >> length;
if (!ss.good()) { std::cerr << "invalid length\n"; return false; }
if (ss.get()!=':') { std::cerr << "expected colon\n"; return false; }
ss >> rating;
if (!ss.good()) { std::cerr << "invalid rating\n"; return false; }
if (ss.get()!=':') { std::cerr << "expected colon\n"; return false; }
std::getline (ss, title);
double sink;
std::cout << title << " ("
<< int(length) << ':' << 60*std::modf (length,&sink)
<< " min), your rating: " << rating << '\n';
return true;
}
int main () {
read ("30.25:5:Vivaldi - The four seasons.ogg");
read ("3.5:5:Cannibal Corpse - Evisceration Plague.ogg");
read ("meh");
return 0;
}
Output:
Vivaldi - The four seasons.ogg (30:15 min), your rating: 5
Cannibal Corpse - Evisceration Plague.ogg (3:30 min), your rating: 5
invalid length
Important: When parsing, you are sailing close to the security risks. Always be conscious and sensible and try to use tested and proven libraries where possible. This also implies that you do not use sscanf, which is not typesafe, error-prone and sometimes hard to get right.
Don't use C if you have C++, and used correctly, iostreams are even more convenient than printf/scanf+co.
You could perhaps do something like
int lastpos = 0;
if sscanf (charveqtur, "%d:%d:%d\tstart\t%n", &this->hour,
&this->minute, &this->second,
&lastpos) > 3 && lastpos >0) {
std::string filename = newline.substr(lastpos);
/* do something with filename */
}
I'm trying to parse a simple string in C++. I know the string contains some text with a colon, followed immediately by a space, then a number. I'd like to extract just the number part of the string. I can't just tokenize on the space (using sstream and <<) because the text in front of the colon may or may not have spaces in it.
Some example strings might be:
Total disk space: 9852465
Free disk space: 6243863
Sectors: 4095
I'd like to use the standard library, but if you have another solution you can post that too, since others with the same question might like to see different solutions.
std::string strInput = "Total disk space: 9852465";
std::string strNumber = "0";
size_t iIndex = strInput.rfind(": ");
if(iIndex != std::string::npos && strInput.length() >= 2)
{
strNumber = strInput.substr(iIndex + 2, strInput.length() - iIndex - 2)
}
For completeness, here's a simple solution in C:
int value;
if(sscanf(mystring.c_str(), "%*[^:]:%d", &value) == 1)
// parsing succeeded
else
// parsing failed
Explanation: the %*[^:] says to read in as many possible characters that aren't colons, and the * suppresses assignment. Then, the integer is read in, after the colon and any intervening white space.
I can't just tokenize on the space (using sstream and <<) because the text in front of the colon may or may not have spaces in it.
Right, but you can use std::getline:
string not_number;
int number;
if (not (getline(cin, not_number, ':') and cin >> number)) {
cerr << "No number found." << endl;
}
Similar to Konrads answer, but using istream::ignore:
int number;
std::streamsize max = std::numeric_limits<std::streamsize>::max();
if (!(std::cin.ignore(max, ':') >> number)) {
std::cerr << "No number found." << std::endl;
} else {
std::cout << "Number found: " << number << std::endl;
}
I'm surprised that no one mentioned regular expressions. They were added as part of TR1 and are included in Boost as well. Here's the solution using regex's
typedef std::tr1::match_results<std::string::const_iterator> Results;
std::tr1::regex re(":[[:space:]]+([[:digit:]]+)", std::tr1::regex::extended);
std::string str("Sectors: 4095");
Results res;
if (std::tr1::regex_search(str, res, re)) {
std::cout << "Number found: " << res[1] << std::endl;
} else {
std::cerr << "No number found." << std::endl;
}
It looks like a lot more work but you get more out of it IMHO.
const std::string pattern(": ");
std::string s("Sectors: 4095");
size_t num_start = s.find(pattern) + pattern.size();