I'm writing a program which makes calculations based on commands, but i'm having a little trouble with the vector's range.
Basically i am entering integers into a vector, a sequence of integers each on a new line, and for example if i enter the command "sum" it gets the last two elements of the vector (the sequence of integers) sums them, deletes them from the sequence and adds to the sequence the new number.
Example:
1
2
4
5
sum
end (this command ends my program)
Output:
1
2
9
Here is the code:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#define CONSOLE_LOG(x) std::cout << x
#define COMMAND_END command[0]
#define COMMAND_SUM command[1]
#define COMMAND_SUBTRACT command[2]
#define COMMAND_CONCAT command[3]
#define COMMAND_DISCARD command[4]
#define COMMAND_DISPSEQ command[5]
std::string sum(std::string& x, std::string& y, std::vector<std::string>& vec)
{
int xInt = atoi(x.c_str());
int yInt = atoi(y.c_str());
int result = xInt + yInt;
std::ostringstream os;
std::string strResult;
os << result;
strResult = os.str();
vec.erase(vec.end() - 1);
vec.erase(vec.end() - 1);
return strResult;
}
/*
std::string subtract(std::string& x, std::string& y)
{
}
std::string concat(std::string& x, std::string& y)
{
}
std::string discard(std::string& x, std::string& y)
{
}
*/
void dispseq(std::vector<std::string>& vec)
{
std::vector<std::string>::const_iterator iter;
for (iter = vec.begin(); iter != vec.end(); iter++)
{
std::cout << *iter << std::endl;
}
}
void enterSequence()
{
std::vector<std::string> command =
{
"end",
"sum",
"subtract",
"concat",
"discard",
"dispseq"
};
std::vector<std::string> sequence;
std::string input;
std::string a = sequence[sequence.size() - 1];
std::string b = sequence[sequence.size() - 2];
do
{
std::cin >> input;
sequence.emplace_back(input);
if (input == COMMAND_END)
{
sequence.erase(sequence.end() - 1);
}
if (input == COMMAND_SUM)
{
sequence.emplace_back(sum(a, b, sequence));
}
dispseq(sequence);
} while (input != COMMAND_END);
}
int main()
{
enterSequence();
std::cin.get(); std::cin.get();
return 0;
}
And here is my problem. Of course i need to define the last two elements of the vector, and i do it with
std::string a = sequence[sequence.size() - 1];
std::string b = sequence[sequence.size() - 2];
But it gives me an exception, and tells me i'm out of range. I guess im not supposed to pass a size of a vector, which still doesn't have one.
How can i write it then?
a and b are being initialized to a negative index of your vector. You can fix that by modifying your do-while loop.
std::string a;
std::string b;
do
{
if(sequence.size() >= 2)
{
b = sequence[sequence.size() - 2];
a = sequence[sequence.size() - 1];
}
else if(sequence.size() >= 1)
{
a = sequence[sequence.size() - 1]
}
std::cin >> input;
sequence.emplace_back(input);
if (input == COMMAND_END)
{
sequence.erase(sequence.end() - 1);
}
if (input == COMMAND_SUM)
{
sequence.emplace_back(sum(a, b, sequence));
}
dispseq(sequence);
} while (input != COMMAND_END);
Related
What I have done is created a global array to store the reversed string.
#include <bits/stdc++.h>
using namespace std;
char arr[10];
int c = 1;
string Reverser(string z)
{
arr[c] = z[(z.size() - c)];
c++;
if (c == (z.size() + 1))
{
return 0;
}
else
{
Reverser(z);
}
return 0;
}
int main()
{
string z;
cin >> z;
string Reverser(z);
for (int i = 1; i <= z.size(); i++)
{
cout << arr[i];
}
return 0;
}
I have also tried to dry run it but I can't really find any error.
You can use a std::stringstream and pass it by reference in your recursive function. Also, you can pass the string by reference.
#include <iostream>
#include <string>
#include <sstream>
void reverse(const std::string& a, std::stringstream& ss, unsigned int pos)
{
ss << a[pos];
if (pos == 0) return;
reverse(a, ss, pos - 1);
}
void reverse(const std::string& a, std::stringstream& ss)
{
reverse(a, ss, a.length() - 1);
}
int main()
{
std::stringstream ss;
std::string input = "Hello";
reverse(input, ss);
std::cout << ss.str() << std::endl;
}
I'm trying to write a function whose first parameter is a string and the second parameter is vector of real numbers. The function should return as a result a new string in which each occurrence replaces the sequences "%d" or "%f" with one number each from the vector, in the order in which they appear. In doing so, if the sequence is "%d", any decimals in the number are truncated, while in the sequence "%f" they are retained.
For example, if the string reads “abc%dxx%fyy %d” and if the vector contains the numbers 12.25, 34.13, 25 and 47, the new string should read “abc12xx34.13yy 25” (data 47 which is “redundant” is simply ignored).
#include <iostream>
#include <string>
#include <vector>
std::string Replace(std::string s, std::vector < double > vek) {
std::string str;
int j = 0;
for (int i = 0; i < s.length(); i++) {
while (s[i] != '%' && i < s.length()) {
if (s[i] != 'f' && s[i] != 'd')
str += s[i];
i++;
}
if (s[i] == '%' && (s[i + 1] == 'd' || s[i + 1] == 'f')) {
if (s[i + 1] == 'd')
str += (std::to_string(int(vek[j])));
if (s[i + 1] == 'f') {
std::string temp = std::to_string(vek[j]);
int l = 0;
while (temp[l] != '0') {
str += temp[l];
l++;
}
}
j++;
if (j > vek.size())
throw std::range_error("Not enough elements");
if (i == s.length()) break;
}
}
return str;
}
int main() {
try {
std::cout<<Replace("abc%dxx%fyy %d",{12.25, 34.13, 25});
std::cout << "\n" << "abc12xx34.13yy 25";
} catch (std::range_error e) {
std::cout << e.what();
}
return 0;
}
OUTPUT:
abc12xx34.13yy 25
abc12xx34.13yy 25
Output is correct. How could I modify this to work with less lines of code? Is there any way to make this more elegant and efficient?
You could use:
regular expressions to search for the pattern (%d|%f), i.e., %d or %f, and
a string stream to create the string to return.
Going into some more detail:
The code is basically a while (std::regex_search).
std::regex_search will return whatever was in the input string before the matched pattern (what you want in the output string), the matched pattern (what you will need to check in order to decide if you want to write out an int or a double), and whatever is left to parse.
By using std::ostringstream, you can simply write out ints or doubles without converting them to strings yourself.
vek.at() will throw an std::out_of_range exception if you run out of data in the vector.
Notice as well that, whereas for this implementation it's good to pass the string s by value (since we are modifying it within the function), you should pass vek as a const reference to avoid a copy of the whole vector.
[Demo]
#include <iostream>
#include <regex>
#include <stdexcept>
#include <sstream>
#include <string>
#include <vector>
std::string Replace(std::string s, const std::vector<double>& vek) {
std::regex pattern{"(%d|%f)"};
std::smatch match{};
std::ostringstream oss{};
for (auto i{0}; std::regex_search(s, match, pattern); ++i) {
oss << match.prefix();
auto d{vek.at(i)};
oss << ((match[0] == "%d") ? static_cast<int>(d) : d);
s = match.suffix();
}
return oss.str();
}
int main() {
try {
std::cout << Replace("abc%dxx%fyy %d", {12.25, 34.13, 25});
std::cout << "\n"
<< "abc12xx34.13yy 25";
} catch (std::out_of_range& e) {
std::cout << e.what();
}
}
// Outputs:
//
// abc12xx34.13yy 25
// abc12xx34.13yy 25
[EDIT] A possible way to do it without std::regex_search would be to search for the (%d|%f) pattern manually, using std::string::find in a loop until the end of the string is reached.
The code below takes into account that:
the input string could not have that pattern, and that
it could have a % character followed by neither d nor f.
[Demo]
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
std::string Replace(std::string s, const std::vector<double>& vek) {
std::ostringstream oss{};
size_t previous_pos{0};
size_t pos{0};
auto i{0};
while (previous_pos != s.size()) {
if ((pos = s.find('%', previous_pos)) == std::string::npos) {
oss << s.substr(previous_pos);
break;
}
oss << s.substr(previous_pos, pos - previous_pos);
bool pattern_found{false};
if (s.size() > pos + 1) {
auto c{s[pos + 1]};
if (c == 'd') {
oss << static_cast<int>(vek.at(i));
pattern_found = true;
} else if (c == 'f') {
oss << vek.at(i);
pattern_found = true;
}
}
if (pattern_found) {
++i;
previous_pos = pos + 2;
} else {
oss << s[pos];
previous_pos = pos + 1;
}
}
return oss.str();
}
int main() {
try {
std::cout << Replace("abc%%dx%x%fyy %d", {12.25, 34.13, 25}) << "\n";
std::cout << "abc%12x%x34.13yy 25\n";
std::cout << Replace("abcdxxfyy d", {12.25, 34.13, 25}) << "\n";
std::cout << "abcdxxfyy d\n";
} catch (std::out_of_range& e) {
std::cout << e.what();
}
}
// Outputs:
//
// abc%12x%x34.13yy 25
// abc%12x%x34.13yy 25
// abcdxxfyy d
// abcdxxfyy d
#include <iostream>
#include <vector>
#include <string>
std::string replace(std::string str, std::vector<double> vec) {
std::string result = "";
int i = 0;
// loop through the string
while (i < str.size()) {
// if the current character is a %
if (str[i] == '%') {
// if the next character is a d
if (str[i+1] == 'd') {
// if the vector is not empty
if (vec.size() > 0) {
// add the first element of the vector to the result
result += std::to_string(vec[0]);
// remove the first element of the vector
vec.erase(vec.begin());
}
// move the index to the next character
i += 2;
}
// if the next character is a f
else if (str[i+1] == 'f') {
// if the vector is not empty
if (vec.size() > 0) {
// add the first element of the vector to the result
result += std::to_string(vec[0]);
// remove the first element of the vector
vec.erase(vec.begin());
}
// move the index to the next character
i += 2;
}
// if the next character is not a d or f
else {
// add the current character to the result
result += str[i];
// move the index to the next character
i += 1;
}
}
// if the current character is not a %
else {
// add the current character to the result
result += str[i];
// move the index to the next character
i += 1;
}
}
// return the result
return result;
}
int main() {
std::vector<double> vec = {12.25, 34.13, 25, 47};
std::string str = "abc%dxx%fyy %d";
std::cout << replace(str, vec);
return 0;
}
I'm new to C++ and i just wrote a function to tell me if certain characters in a string repeat or not:
bool repeats(string s)
{
int len = s.size(), c = 0;
for(int i = 0; i < len; i++){
for(int k = 0; k < len; k++){
if(i != k && s[i] == s[k]){
c++;
}
}
}
return c;
}
...but i can't help but think it's a bit congested for what it's supposed to do. Is there any way i could write such a function in less lines?
Is there any way i could write such a function in less lines?
With std, you might do:
bool repeats(const std::string& s)
{
return std::/*unordered_*/set<char>{s.begin(), s.end()}.size() != s.size();
}
#include <algorithm>
bool repeats(std::string s){
for (auto c : s){
if(std::count(s.begin(), s.end(), c) - 1)
return true;
}
return false;
}
Assuming you are not looking for repeated substrings :
#include <iostream>
#include <string>
#include <set>
std::set<char> ignore_characters{ ' ', '\n' };
bool has_repeated_characters(const std::string& input)
{
// std::set<char> is a collection of unique characters
std::set<char> seen_characters{};
// loop over all characters in the input string
for (const auto& c : input)
{
// skip characters to ignore, like spaces
if (ignore_characters.find(c) == ignore_characters.end())
{
// check if the set contains the character, in C++20 : seen_characters.contains(c)
// and maybe you need to do something with "std::tolower()" here too
if (seen_characters.find(c) != seen_characters.end())
{
return true;
}
// add the character to the set, we've now seen it
seen_characters.insert(c);
}
}
return false;
}
void show_has_repeated_characters(const std::string& input)
{
std::cout << "'" << input << "' ";
if (has_repeated_characters(input))
{
std::cout << "has repeated characters\n";
}
else
{
std::cout << "doesn't have repeated characters\n";
}
}
int main()
{
show_has_repeated_characters("Hello world");
show_has_repeated_characters("The fast boy");
return 0;
}
std::string str;
... fill your string here...
int counts[256]={0};
for(auto s:str)
counts[(unsigned char)s]++;
for(int i=0;i<256;i++)
if(counts[i]>1) return true;
return false;
6 lines instead of 9
O(n+256) instead of O(n^2)
This is your new compact function :
#include <iostream>
#include <algorithm>
using namespace std;
int occurrences(string s, char c) {
return count(s.begin(), s.end(), c); }
int main() {
//occurrences count how many times char is repetated.
//any number other than 0 is considered true.
occurrences("Hello World!",'x')?cout<<"repeats!":cout<<"no repeats!";
//It is equal write
//
// if(occurrences("Hello World!",'x'))
// cout<<"repeats!";
// else
// cout<<"no repeats!";
//So to count the occurrences
//
// int count = occurrences("Hello World!",'x');
}
Given a string with repeating characters and a burst length, output the string such that the count of the same adjacent characters in the string is less than the burst length.
Input : abbccccdd, burstLen = 3
Correct Output : abbdd
My Output: abbd
Input : abbcccdeaffff, burstLen = 3
Correct Output: abbdea
My Output: abbea
//Radhe krishna ki jytoi alokik
#include <bits/stdc++.h>
using namespace std;
string solve(string s, int burstLen)
{
stack<pair<char, int>> ms;
for (int i = 0; i < s.size(); i++)
{
if (!ms.empty() && ms.top().first == s[i])
{
int count = ms.top().second;
ms.push({s[i], count + 1});
}
else
{
if(ms.empty() == true || ms.top().first != s[i])
{
if(!ms.empty() && ms.top().second >= burstLen)
{
int count = ms.top().second;
while(!ms.empty() && count--)
ms.pop();
//(UPDATE)
ms.push({s[i], 1});
}
else
ms.push({s[i], 1});
}
}
}
if(!ms.empty() and ms.top().second >= burstLen)
{
int count = ms.top().second;
while(!ms.empty() && count--)
ms.pop();
}
string ans = "";
while (!ms.empty())
{
ans += ms.top().first;
ms.pop();
}
reverse(ans.begin(), ans.end());
return ans;
}
int main()
{
string s;
int burstLen;
cin >> s;
cin >> burstLen;
cout << solve(s, burstLen) << "\n";
}
It would be better at least to use the container adapter std::queue instead of std::stack because there would not be a need to call the algorithm std::reverse.
Moreover if items of the stack contain the second data member that stores frequencies then you could just increase this data member for repeated characters instead of placing each repeated character in the stack.
For example this code snippet in your program
if (!ms.empty() && ms.top().first == s[i])
{
int count = ms.top().second;
ms.push({s[i], count + 1});
}
makes the function definition too complicated and unclear because the same character is pushed on the stack with different frequencies.
Nevertheless if you want to use the container adapter std::stack the function definition could look simpler. You are not using features of the class std::string.
Here is a demonstrative program that shows how the function could be written using your approach with std::stack.
#include <iostream>
#include <string>
#include <utility>
#include <stack>
#include <iterator>
#include <algorithm>
std::string solve( const std::string &s, size_t burstLen )
{
std::stack<std::pair<char, size_t>> stack;
for ( const auto &c : s )
{
if ( stack.empty() || stack.top().first != c )
{
stack.push( { c, 1 } );
}
else
{
++stack.top().second;
}
}
std::string ans;
while ( !stack.empty() )
{
if ( stack.top().second < burstLen )
{
ans.append( stack.top().second, stack.top().first );
}
stack.pop();
}
std::reverse( std::begin( ans ), std::end( ans ) );
return ans;
}
int main()
{
std::cout << solve( "abbccccdd", 3 ) << '\n';
std::cout << solve( "abbcccdeaffff", 3 ) << '\n';
}
The program output is
abbdd
abbdea
It is interesting to use the stack when after removing a sequence of characters that is not less than the burst length you get from the left and right side sub-sequences anew sequence that again is not less than burst length and you need also to remove it.
In this case you can use two stacks.
Here is a demonstrative program.
#include <iostream>
#include <string>
#include <utility>
#include <stack>
#include <iterator>
#include <algorithm>
std::string solve( const std::string &s, size_t burstLen )
{
std::stack<std::pair<char, size_t>> stack_in;
for ( const auto &c : s )
{
if ( stack_in.empty() || stack_in.top().first != c )
{
stack_in.push( { c, 1 } );
}
else
{
++stack_in.top().second;
}
}
std::stack<std::pair<char, size_t>> stack_out;
while ( !stack_in.empty() )
{
if ( !stack_out.empty() && stack_out.top().first == stack_in.top().first )
{
if ( stack_out.top().second + stack_in.top().second < burstLen )
{
stack_out.top().second += stack_in.top().second;
}
else
{
stack_out.pop();
}
}
else if ( stack_in.top().second < burstLen )
{
stack_out.push( stack_in.top() );
}
stack_in.pop();
}
std::string ans;
while ( !stack_out.empty() )
{
ans.append( stack_out.top().second, stack_out.top().first );
stack_out.pop();
}
return ans;
}
int main()
{
std::cout << solve( "abbccccdd", 3 ) << '\n';
std::cout << solve( "abbcccdeaffff", 3 ) << '\n';
std::cout << solve( "aabcddeeedccbaa", 3 );
}
The program output is
abbdd
abbdea
aabbaa
I gave it a try but it looks complicated so I suggest making a simpler function using a few functions from the standard library.
Example:
#include <algorithm>
#include <iostream>
#include <initializer_list>
#include <iterator>
std::string solve(const std::string& in, size_t burstlen) {
std::string retval;
for(std::string::const_iterator begin = in.cbegin(), bend;
begin != in.end();
begin = bend)
{
// find the first char not equal to the current char
bend = std::find_if_not(std::next(begin), in.end(),
[curr=*begin](char ch){ return ch==curr; });
if(std::distance(begin, bend) < burstlen) {
// length ok, append it
retval.append(begin, bend);
}
}
return retval;
}
int main() {
std::initializer_list<std::string> tests{
"abbccccdd", "abbcccdeaffff"};
for(auto test : tests) std::cout << solve(test, 3) << '\n';
}
Output:
abbdd
abbdea
My Approach to the Solution :
Create a Stack of pair which consists of character and character count
If the Stack is empty or the top element of the stack is not equal to the current element in the string
Case 1: if the frequency of the top element of the stack is greater than or equal to k, store it in a variable say count, Pop the element of Stack count times.
Case 2: if the Stack is Empty, then simply push the element in stack with frequency 1.
Upon Traversing the complete string, if the top element of the stack is having a frequency greater than bursten, start removing elements from the stack (count) number of times.
Now, we have leftout elements in the stack, Start popping them and store them in a string and reverse the string to preserve the order.
Return the new string.
UPDATE : SOLVED. Missing one line in this condition if(ms.empty() == true || ms.top().first != s[i]) After popping the elements, We also have to insert the present element with character frequency 1.
#include<iostream>
#include<stack>
using namespace std;
string solve(string s, int burstLen)
{
stack<pair<char, int>> ms;
for (int i = 0; i < s.size(); i++)
{
if (!ms.empty() && ms.top().first == s[i])
{
int count = ms.top().second;
ms.push({s[i], count + 1});
}
else
{
if(ms.empty() == true || ms.top().first != s[i])
{
if(!ms.empty() && ms.top().second >= burstLen)
{
int count = ms.top().second;
while(!ms.empty() && count--)
ms.pop();
ms.push({s[i], 1});
}
else
ms.push({s[i], 1});
}
}
}
if(!ms.empty() and ms.top().second >= burstLen)
{
int count = ms.top().second;
while(!ms.empty() && count--)
ms.pop();
}
string ans = "";
while (!ms.empty())
{
ans += ms.top().first;
ms.pop();
}
reverse(ans.begin(), ans.end());
return ans;
}
int main()
{
int t;
cin >> t;
while(t--)
{
string s;
int burstLen;
cin >> s >>burstLen;
cout << solve(s, burstLen) << "\n";
}
}
private void solve(){
System.out.printf("%s\n", solve("abbccccdd", 3));
System.out.printf("%s\n", solve("abbcccdeaffff", 3));
}
private LinkedList<Node> addToQueue(String S){
int N = S.length();
LinkedList<Node> queue = new LinkedList<>();
queue.addFirst(new Node(S.charAt(0), 1));
for(int i=1;i<N;i++){
if(!queue.isEmpty() && queue.getFirst().val==S.charAt(i)) {
queue.getFirst().count +=1;
} else {
queue.addFirst(new Node(S.charAt(i), 1));
}
}
return queue;
}
private String solve(String S, int K){
if(S==null || S.length()==0) return "";
int N = S.length();
LinkedList<Node> queue = addToQueue(S);
StringBuilder buf = new StringBuilder();
while(!queue.isEmpty()) {
Node node = queue.removeLast();
int count = node.count;
if(count>=K) continue;
if(isSame(queue, buf)){
while(isSame(queue, buf)) {
count += queue.getLast().count;
queue.removeLast();
}
if(count>=K) buf.deleteCharAt(buf.length()-1);
else {
while(count-->0){
buf.append(node.val);
}
}
} else {
if(count>=K) continue;
while(count-->0){
buf.append(node.val);
}
}
}
return buf.toString();
}
private boolean isSame(LinkedList<Node> queue, StringBuilder buf){
if(queue.isEmpty() || buf.length()==0) return false;
return queue.getLast().val == buf.charAt(buf.length()-1);
}
class Node {
char val;
int count;
public Node(char c, int count){
this.val = c;
this.count = count;
}
}
Here is my code. It is supposed to get input until end of input and place that input into the string data. Then it is supposed to tokenize the input using the delimiter "#". I then repeatedly call my function nexttoken() to store the tokens in variables.
std::istream_iterator<char> it(std::cin);
std::istream_iterator<char> end;
std::string data(it,end);
std::string delimiter = "#";
StringTokenizer strtok(data,delimiter);
std::string t1 = strtok.nextToken();
std::string t2 = strtok.nextToken();
This all works when I pass a file through on command line like this:
program.exe <testcase1.txt
testcase1.txt
S A B #
S -> a A #
S -> z B #
A -> b B c B #
B -> d A #
##
output
S A B
a: 1
b: 1
c: 1
d: 1
z: 1
everything checks out and works.
My problem is this: When I push run in my IDE I can type the input in manually but when I do there is no way to make the program accept the input except if I press ctrl-z. This problem also persists in linux when I pass a file through in terminal, it just hangs there letting me type infinite lines.
here is a smaller version of my code that only counts 3 tokens and only checks for a,b and c
main.cpp
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
#include <cstddef>
#include "StringTokenizer.h"
int countSubstring(const std::string& str, const std::string& sub)
{
if (sub.length() == 0) return 0;
int count = 0;
for (size_t offset = str.find(sub); offset != std::string::npos;
offset = str.find(sub, offset + sub.length()))
{
++count;
}
return count;
}
int main(int argc, char* argv[1])
{
int task;
if (argc < 2)
{
std::cout << "Error: missing argument\n";
return 1;
}
task = atoi(argv[1]);
switch(task){
case 0:
{
std::istream_iterator<char> it(std::cin);
std::istream_iterator<char> end;
std::string data(it,end);
std::string delimiter = "#";
StringTokenizer strtok(data,delimiter);
int a = 0;
int b = 0;
int c = 0;
//reading the first token and puting it in tk1
std::string t1 = strtok.nextToken();
std::string tk1(t1);
tk1.erase(0, tk1.find_first_not_of(" "));
tk1.erase(tk1.find_last_not_of(" ")+1);
// token 2 and 3 are different because 1 is always the same format
std::string t2 = strtok.nextToken();
std::string tk2(t2);
if(countSubstring(tk2,"a") > 0)
{
a = a + 1;
}
if(countSubstring(tk2,"b") > 0)
{
b=b + 1;
}
if(countSubstring(tk2,"c") > 0)
{
c=c + 1;
}
std::string t3 = strtok.nextToken();
std::string tk3(t3);
if(countSubstring(tk3,"a") > 0)
{
a = a + 1;
}
if(countSubstring(tk3,"b") > 0)
{
b=b + 1;
}
if(countSubstring(tk3,"c") > 0)
{
c=c + 1;
}
// this is where the output is
std::cout << tk1 << std::endl;
if(a > 0)
{
std::cout << "a: " << a <<std::endl;
}
if(b > 0)
{
std::cout << "b: " << b <<std::endl;
}
if(c > 0)
{
std::cout << "c: " << c <<std::endl;
}
}
break;
//////////////////////////////////////////////////
case 1:
break;
case 2:
break;
default:
std::cout << "Error: unrecognized task number " << task << "\n";
break;
}
return 0;
}
StringTokenizer.h
#ifndef INCLUDE_STRINGTOKENIZER_H
#define INCLUDE_STRINGTOKENIZER_H
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
class StringTokenizer
{
public:
StringTokenizer(const std::string& _str, const std::string& _delim);
~StringTokenizer(){};
std::string nextToken();
std::string nextToken(const std::string& delim);
private:
std::string token_str;
std::string delim;
};
#endif
StringTokenizer.cpp
#include "StringTokenizer.h"
StringTokenizer::StringTokenizer(const std::string& _str, const std::string& _delim)
{
if ((_str.length() == 0) || (_delim.length() == 0)) return;
token_str = _str;
delim = _delim;
/*
Remove sequential delimiter
*/
unsigned int curr_pos = 0;
while(true)
{
if ((curr_pos = token_str.find(delim,curr_pos)) != std::string::npos)
{
curr_pos += delim.length();
while(token_str.find(delim,curr_pos) == curr_pos)
{
token_str.erase(curr_pos,delim.length());
}
}
else
break;
}
/*
Trim leading delimiter
*/
if (token_str.find(delim,0) == 0)
{
token_str.erase(0,delim.length());
}
/*
Trim ending delimiter
*/
curr_pos = 0;
if ((curr_pos = token_str.rfind(delim)) != std::string::npos)
{
if (curr_pos != (token_str.length() - delim.length())) return;
token_str.erase(token_str.length() - delim.length(),delim.length());
}
}
std::string StringTokenizer::nextToken()
{
if (token_str.length() == 0)
return "";
std::string tmp_str = "";
unsigned int pos = token_str.find(delim,0);
if (pos != std::string::npos)
{
tmp_str = token_str.substr(0,pos);
token_str = token_str.substr(pos+delim.length(),token_str.length()-pos);
}
else
{
tmp_str = token_str.substr(0,token_str.length());
token_str = "";
}
return tmp_str;
}
std::string StringTokenizer::nextToken(const std::string& delimiter)
{
if (token_str.length() == 0)
return "";
std::string tmp_str = "";
unsigned int pos = token_str.find(delimiter,0);
if (pos != std::string::npos)
{
tmp_str = token_str.substr(0,pos);
token_str = token_str.substr(pos + delimiter.length(),token_str.length() - pos);
}
else
{
tmp_str = token_str.substr(0,token_str.length());
token_str = "";
}
return tmp_str;
}
1: How do I change my code so that It will stop searching for input when I am done typing? or when it can see ## has been typed? (## marks the end of the input)
2: Is this even possible with my current code?
Both Linux and my IDE compile with g++
You are using input streams from std::cid to read the data, which will only stop when you reach the end-of-file, which is why you need to terminate the input with Ctrl-z in windows and Ctrl-d in Linux.
The simplest change is reading line by line and processing them independently. That will allow you to read the termination marker ## and not proceed further (assuming that the marker is actually two # followed by a new line).
std::string line;
while (std::getline(std::cin, line)) {
if (line == "##") break;
// process a single line
}
If there's no guarantee that the delimiter is followed by a single line, you may need to read character by character, but that is unlikely.