I am trying to create a c++ program that detects when white space has been input to a cin line, and then detects what word comes after it.
I am only showing my function here:
int lineFunction (string line) {
if (/*whatever characters, then whitespace, and the letter ‘a’ is read*/) {
return 0;
}else if (/*whatever characters, then whitespace followed by the letter ‘b’*/) {
return 1;
}else {
return 2;
}
}
So if the input is, say: abc a then the output should be 0, and if the input is abc b then the output should be 1, otherwise it should be 2.
I would also like to know if this function could be ‘stacked’, like if I could have multiple white spaces and multiple words.
You can use std::find_if and std::isspace
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
int lineFunction(std::string line) {
auto begin = std::find_if(std::begin(line), std::end(line), [](unsigned char c){ return std::isspace(c); });
if (begin == std::end(line) || ++begin == std::end(line)) return 2;
auto end = std::find_if(begin, std::end(line), [](unsigned char c){ return std::isspace(c); });
std::string word(begin, end);
if (word == "a") {
return 0;
} else if (word == "b") {
return 1;
} else {
return 2;
}
}
int main() {
std::string line = "abc a";
std::cout << lineFunction(line);
}
Related
I need a program to take a string and replace spaces with increasing numbers.
#include <cstring>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
// Get the String
string str = "this essay needs each word to be numbered";
int num = 1;
string x = num;
int i = 0;
// read string character by character.
for (i < str.length(); ++i) {
// Changing the loaded character
// to a number if it's a space.
if (str[i] == ' ') {
str[i] = x;
++num
}
}
// testing outputs
cout << str << endl;
cout << num << endl;
ofstream file;
file.open ("numbered.txt");
file << str;
file.close();
return 0;
}
I had it at the point where it could replace spaces with a letter or symbol and save to a new file but when I tried to make it a number it stopped working. I would need it to say "this1essay2needs3each4word5to6be7numbered
For ease and clarity, change your approach.
Put the string into an istringstream
Extract each space-separated substring and place into an std::vector<string>
Feed the contents of the vector into a stringstream and
use std::to_string(num) to add the numbers between the substrings
e.g.:
std::string str = "this essay needs each word to be numbered";
int num = 1;
std::istringstream istr(str);
std::string temp;
std::vector<std::string> substrs;
while (istr >> temp)
{
substrs.push_back(temp);
}
std::stringstream ostr;
for (auto&& substr : substrs)
{
ostr << substr << std::to_string(num++);
}
Let's break the problem down into parts. We can make a SpaceReplacer object that does the replacement. It has an Output, which it can use as a function to output characters:
template<class Output>
struct SpaceReplacer {
Output output;
int num_spaces;
void input(char c) {
if(c == ' ') {
auto num_as_string = std::to_string(num_spaces);
num_spaces += 1;
for(char digit : num_as_string) {
output(digit);
}
}
else {
output(c);
}
}
};
Every time you input a character, it either outputs the character you input, or it outputs the digits of the number (if the character was a space).
We should write a helper function to make SpaceReplacers:
template<class Output>
SpaceReplacer<Output> makeReplacer(Output output_func) {
return SpaceReplacer<Output>{output_func, 0};
}
Reading one string, returning new string
It's now easy to write a function that replaces spaces in a string.
std::string replaceSpaces(std::string const& input) {
std::string output_string;
// We output chars by appending them to the output string
auto output_func = [&](char c) { output_string += c; };
auto replacer = makeReplacer(output_func);
for(char c : input) {
replacer.input(c);
}
return output_string;
}
Reading input from file, replacing spaces and returning a string
Because we wrote a really generic SpaceReplacer class, we can modify the function so that it'll read input directly from a FILE*
std::string replaceSpaces(FILE* file) {
std::string output_string;
auto output_func = [&](char c) { output_string += c; };
auto replacer = makeReplacer(output_func);
while(true) {
int input_char = fgetc(file);
if(input_char == EOF) {
break;
}
replacer.input(input_char);
}
return output_string;
}
Reading input from one file, immediately appending it to different file with spaces replaced
We can also read directly from one file, and output directly to another file, with no delay. This might be useful if you were processing a very large amount of data.
void replaceSpaces(FILE* input_file, FILE* output_file) {
auto output_func = [=](char c) { fputc(c, output_file); };
auto replacer = makeReplacer(output_func);
while(true) {
int input_char = fgetc(input_file);
if(input_char == EOF) {
break;
}
replacer.input(input_char);
}
}
In this case, you need to use another string for the result.
#include <cstring>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
// Get the String
string result, str = "this essay needs each word to be numbered qwe qwe wqe qwe qwe qwe q";
int num = 0;
int i;
// read string character by character.
for (i=0; i < str.length(); i++) {
// Changing the loaded character
// to a number if it's a space.
if (str[i] == ' ')
result+=std::to_string(++num);
else
result+=str[i];
}
// testing outputs
cout<<result<<endl;
cout<<num;
ofstream file;
file.open ("numbered.txt");
file << result;
file.close();
return 0;
}
You have to replace it with a character, not by a number.
str[i] = num+'0';
I have to make a function which reverses words that have been written in an char array.
char reverse(char m[50]) {
for (int i = 0; i <= m['\0']; i++) {
for (int j = m['\0']-1; j >= m[0]; j--) {
m[i] = m[j];
}
}
}
This is the code I have in mind which would output something like this:
Input: I am new
Output: wen ma I
What I need is:
Input: I am new
Output: I ma wen
Hope you understood what I meant here as I am quite new to programming and really need help with this.
If you want a c++ solution then the following should work:
#include <iostream>
#include <string>
#include <algorithm>
int main()
{
std::string str = "I am new";
auto begin = str.begin();
while (begin != str.end())
{
auto end = std::find(begin, str.end(), ' ');
std::reverse(begin, end);
if (end == str.end())
{
break;
}
begin = end + 1;
}
std::cout << str << "\n";
}
Since not only a space may delimiter words also other whitespaces should be considered.
#include <iostream>
bool IsWhiteSpaceOrEnd(char c) {
switch (c) {
case ' ':
case '\t':
case '\r':
case '\n':
case 0:
return true;
}
return false;
}
void ReverseWord(char* begin, char* end) {
--end;
while (begin < end) {
char temp = *begin;
*begin = *end;
*end = temp;
++begin;
--end;
}
}
void ReverseEachWord(char* str) {
char* begin = str;
while (0 != *begin) {
char* end = begin + 1;
// find next end of word
while (!IsWhiteSpaceOrEnd(*end)) {
++end;
}
// reverse the word between begin and end
ReverseWord(begin, end);
begin = end;
// go forward to the next begin of a word
while ((0 != *begin) && IsWhiteSpaceOrEnd(*begin)) {
++begin;
}
}
}
int main(int argc, char** argv)
{
char* text = strdup("I am new");
ReverseEachWord(text);
return 0;
}
I'd convert the char array input and output to strings, at least for processing. You can convert the result back to char array if you really need that.
string ReverseText(const string& text)
{
string word(""), result("");
for (const auto& character : text)
{
if (!isspace(character))
word += character; // Build the next word to reverse
else
{
std::reverse(word.begin(), word.end()); // Reverse the completed word
result += word + character; // Add your processed word to the result
word = ""; // Clear word variable for next iteration
}
}
std::reverse(word.begin(), word.end()); // Don't forget the last word built
return result + word;
}
I'm working on a function that uses recursion in order to delete duplicate characters in a string. Problem is, I'm not sure how to keep passing a string along in order to keep comparing adjacent characters without cutting the string somehow. Here's what I have so far:
string stringClean(const string& str)
{
string s1 = str;
if (/*first char == next char*/)
s1.at(/*first char*/) = "";
return stringClean(s1);
else
return s1;
}
As an example, stringClean("yyzzza") should return "yza". Any tips on how I should proceed?
C++
Here's what I just thought about
#include <iostream>
#include <string>
std::string rec(std::string &word, int index);
std::string rec(std::string word) {
if(word.length() <= 1) {
return word;
}
return word[0] + rec(word, 1);
}
std::string rec(std::string &word, int index) {
if(index == word.length()) {
return "";
}
return (word[index] != word[index-1] ? std::string(1, word[index]) : "") + rec(word, index+1);
}
int main() {
std::cout << rec("aaabbbbcccddd") << std::endl;
}
For one line recursion lovers:
std::string rec(std::string &word, int index) {
return index == word.length() ? "" : (word[index] != word[index-1] ? std::string(1, word[index]) : "") + rec(word, index+1);
}
Algorithm:
Start from the leftmost character and remove duplicates at the left corner if there are any.
If the length of the string is zero or one then return the string.
Check the leftmost character in the starting substring. If it is present then
Recur for a string of length n-1 (string without last character).
If the leftmost character is not present in the starting substring, then
Recur for the remaining string and store the unique character.
Implementation:
#include <string>
#include <iostream>
using namespace std;
string removeDups(string s) {
if(s.length() <= 1) return s;
if(s.substr(0, s.length() - 1).find(s.substr(s.length() - 1, s.length())) != string::npos) {
return removeDups(s.substr(0, s.length() - 1));
} else {
return removeDups(s.substr(0, s.length() - 1)) + s.substr(s.length() - 1, s.length());
}
}
int main() {
string s;
cin >> s;
cout << removeDups(s);
return 0;
}
So essentially what I want to do is erase all the whitespace from an std::string object, however excluding parts within speech marks and quote marks (so basically strings), eg:
Hello, World! I am a string
Would result in:
Hello,World!Iamastring
However things within speech marks/quote marks would be ignored:
"Hello, World!" I am a string
Would result in:
"Hello, World!"Iamastring
Or:
Hello,' World! I' am a string
Would be:
Hello,' World! I'amastring
Is there a simple routine to perform this to a string, either one build into the standard library or an example of how to write my own? It doesn't have to be the most efficient one possible, as it will only be run once or twice every time the program runs.
No, there is not such a routine ready.
You may build your own though.
You have to loop over the string and you want to use a flag. If the flag is true, then you delete the spaces, if it is false, you ignore them. The flag is true when you are not in a part of quotes, else it's false.
Here is a naive, not widely tested example:
#include <string>
#include <iostream>
using namespace std;
int main() {
// we will copy the result in new string for simplicity
// of course you can do it inplace. This takes into account only
// double quotes. Easy to extent do single ones though!
string str("\"Hello, World!\" I am a string");
string new_str = "";
// flags for when to delete spaces or not
// 'start' helps you find if you are in an area of double quotes
// If you are, then don't delete the spaces, otherwise, do delete
bool delete_spaces = true, start = false;
for(unsigned int i = 0; i < str.size(); ++i) {
if(str[i] == '\"') {
start ? start = false : start = true;
if(start) {
delete_spaces = false;
}
}
if(!start) {
delete_spaces = true;
}
if(delete_spaces) {
if(str[i] != ' ') {
new_str += str[i];
}
} else {
new_str += str[i];
}
}
cout << "new_str=|" << new_str << "|\n";
return 0;
}
Output:
new_str=|"Hello, World!"Iamastring|
Here we go. I ended up iterating through the string, and if it finds either a " or a ', it will flip the ignore flag. If the ignore flag is true and the current character is not a " or a ', the iterator just increments until it either reaches the end of the string or finds another "/'. If the ignore flag is false, it will remove the current character if it's whitespace (either space, newline or tab).
EDIT: this code now supports ignoring escaped characters (\", \') and making sure a string starting with a " ends with a ", and a string starting with a ' ends with a ', ignoring anything else in between.
#include <iostream>
#include <string>
int main() {
std::string str("I am some code, with \"A string here\", but not here\\\". 'This sentence \" should not end yet', now it should. There is also 'a string here' too.\n");
std::string::iterator endVal = str.end(); // a kind of NULL pointer
std::string::iterator type = endVal; // either " or '
bool ignore = false; // whether to ignore the current character or not
for (std::string::iterator it=str.begin(); it!=str.end();)
{
// ignore escaped characters
if ((*it) == '\\')
{
it += 2;
}
else
{
if ((*it) == '"' || (*it) == '\'')
{
if (ignore) // within a string
{
if (type != endVal && (*it) == (*type))
{
// end of the string
ignore = false;
type = endVal;
}
}
else // outside of a string, so one must be starting.
{
type = it;
ignore = true;
}
it++;
//ignore ? ignore = false : ignore = true;
//type = it;
}
else
{
if (!ignore)
{
if ((*it) == ' ' || (*it) == '\n' || (*it) == '\t')
{
it = str.erase(it);
}
else
{
it++;
}
}
else
{
it++;
}
}
}
}
std::cout << "string now is: " << str << std::endl;
return 0;
}
Argh, and here I spent time writing this (simple) version:
#include <cctype>
#include <ciso646>
#include <iostream>
#include <string>
template <typename Predicate>
std::string remove_unquoted_chars( const std::string& s, Predicate p )
{
bool skip = false;
char q = '\0';
std::string result;
for (char c : s)
if (skip)
{
result.append( 1, c );
skip = false;
}
else if (q)
{
result.append( 1, c );
skip = (c == '\\');
if (c == q) q = '\0';
}
else
{
if (!std::isspace( c ))
result.append( 1, c );
q = p( c ) ? c : '\0';
}
return result;
}
std::string remove_unquoted_whitespace( const std::string& s )
{
return remove_unquoted_chars( s, []( char c ) -> bool { return (c == '"') or (c == '\''); } );
}
int main()
{
std::string s;
std::cout << "s? ";
std::getline( std::cin, s );
std::cout << remove_unquoted_whitespace( s ) << "\n";
}
Removes all characters identified by the given predicate except stuff inside a single-quoted or double-quoted C-style string, taking care to respect escaped characters.
you may use erase-remove idiom like this
#include <string>
#include <iostream>
#include <algorithm>
int main()
{
std::string str("\"Hello, World!\" I am a string");
std::size_t x = str.find_last_of("\"");
std::string split1 = str.substr(0, ++x);
std::string split2 = str.substr(x, str.size());
split1.erase(std::remove(split1.begin(), split1.end(), '\\'), split1.end());
split2.erase(std::remove(split2.begin(), split2.end(), ' '), split2.end());
std::cout << split1 + split2;
}
I'm a C++ newbie who came from Java, so I need some guidance on some really basic issues I'm stumbling upon as I go.
I'm reading lines from a file, and each line consists of 6 strings/ints, which will be sent as parameters to a temporary variable.
Example:
Local1,Local2,ABC,200,300,asphalt
However, there are two subtypes of variable. One has a string as the last parameter (like 'asphalt' in the example above). The other one has an int instead. I have a method that reads each parameter and sends it to a variable, but how do I detect if the last bit of string is an integer or a string beforehand, so I know if I should send it to a Type1 variable or a Type2 one?
Many thanks!
Since you want to determine the type of the last column, then this ought to work:
#include <iostream>
#include <string>
#include <cstdlib>
#include <vector>
#include <sstream>
#include <cctype>
#include <algorithm>
enum Types {
NONE,
STRING,
INTEGER,
DOUBLE
};
struct Found {
std::string string_val;
int integer_val;
double double_val;
enum Types type;
};
//copied verbatim from:
//http://stackoverflow.com/a/2845275/866930
inline bool isInteger(const std::string &s) {
if(s.empty() || ((!std::isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false;
char * p ;
std::strtol(s.c_str(), &p, 10);
return (*p == 0);
}
//modified slightly for decimals:
inline bool isDouble(const std::string &s) {
if(s.empty() || ((!std::isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false ;
char * p ;
std::strtod(s.c_str(), &p) ;
return (*p == 0);
}
bool isNotAlpha(char c) {
return !(std::isalpha(c));
}
//note: this searches for strings containing only characters from the alphabet
//however, you can modify that behavior yourself.
bool isString (const std::string &s) {
std::string::const_iterator it = std::find_if(s.begin(), s.end(), isNotAlpha);
return (it == s.end()) ? true : false;
}
void determine_last_column (const std::string& str, Found& found) {
//reset found:
found.integer_val = 0;
found.double_val = 0;
found.string_val = "";
found.type = NONE;
std::string temp;
std::istringstream iss(str);
int column = 0;
char *p;
while(std::getline(iss, temp, ',')) {
if (column == 5) {
//now check to see if the column is an integer or not:
if (isInteger(temp)) {
found.integer_val = static_cast<int>(std::strtol(temp.c_str(), &p, 10));
found.type = INTEGER;
}
else if (isDouble(temp)) {
found.double_val = static_cast<double>(std::strtod(temp.c_str(), &p));
found.type = DOUBLE;
}
else if (isString(temp)) {
found.string_val = temp;
found.type = STRING;
}
}
++column;
}
if (found.type == INTEGER) {
std::cout << "An integer was found: " << found.integer_val << std::endl;
}
else if(found.type == DOUBLE) {
std::cout << "A double was found: " << found.double_val << std::endl;
}
else if(found.type == STRING) {
std::cout << "A string was found: " << found.string_val << std::endl;
}
else {
std::cout << "A valid type was not found! Something went wrong..." << std::endl;
}
}
int main() {
std::string line_t1 = "Local1,Local2,ABC,200,300,asphalt";
std::string line_t2 = "Local1,Local2,ABC,200,300,-7000.3";
Found found;
determine_last_column(line_t1, found);
determine_last_column(line_t2, found);
return 0;
}
This outputs and correctly assigns the appropriate value:
A string was found: asphalt
An integer was found: -7000.3
This version works on int, double, string; does not require boost; and, is plain vanilla C++98.
REFERENCES:
UPDATE:
This version now supports both positive and negative numbers that are integers or doubles, in addition to strings.
First, create an array that can store both strings and integers:
std::vector<boost::variant<std::string, int>> items;
Second, split the input string on commas:
std::vector<std::string> strings;
boost::split(strings, input, boost::is_any_of(","));
Last, parse each token and insert it into the array:
for (auto&& string : strings) {
try {
items.push_back(boost::lexical_cast<int>(string));
} catch(boost::bad_lexical_cast const&) {
items.push_back(std::move(string));
}
}