Inserting characters intro a string in C++ - c++

I need to insert a character into a string of letters that are in alphabetical order, and this character has to be placed where it belongs alphabetically.
For example I have the string string myString("afgjz"); and the input code
cout << "Input your character" << endl;
char ch;
cin >> ch;
but how can I make it so that after inputting the char(say b) it is then added to the string on the proper position resulting in the string becoming "abfgjz".

You can use std::lower_bound to find the position to insert.
myString.insert(std::lower_bound(myString.begin(), myString.end(), ch), ch);
A more generic solution would be having a function like
namespace sorted
{
template<class Container, class T>
void insert(Container & object, T const & value)
{
using std::begin;
using std::end;
object.insert(std::lower_bound(begin(object),
end(object), value), value);
}
}
And then use
sorted::insert(myString, ch);

Class std::string has the following insert method (apart from other its insert methods):
iterator insert(const_iterator p, charT c);
So all what you need is to find the position where the new character has to be inserted. If the string has already the same character then there are two approaches: either the new character is inserted before the existent character in the string and in this case you should use standard algorithm std::lower_bound or the new character is inserted after the existent character in the string and in this case you should use standard algorithm std::upper_bound.
Here is a demonstrative program that shows how this can be done using standard algorithm std::upper_bound. You may substitute it for std::lower_bound if you like. Though in my opinion it is better to insert the new character after existent one because in some situation you can avoid moving characters after the target position that to insert the new character.
#include <iostream>
#include <algorithm>
#include <string>
int main()
{
std::string myString( "afgjz" );
char c = 'b';
myString.insert( std::upper_bound( myString.begin(), myString.end(), c ), c );
std::cout << myString << std::endl;
return 0;
}
The program output is
abfgjz

Related

How to search and delete characters in string

I'm trying to convert .fsp files to strings but new .fsp file is very abnormal. It contains some undesirable characters that I want to delete from string. How can I make it?
I have tried to search char in string and delete them but I dont know how to make it.
The string looks like this:
string s;
s = 144˙037˙412˙864;
and I need to make it just like that
s = 144037412864;
So I except result like this:
string s = 144037412864;
Thank you for help.
We can use the remove-erase idiom to remove unnecessary characters from the string! There's a function in <algorithm> called remove_if. What remove_if does is it removes elements that match some predicate. remove_if returns a iterator pointing to the new end of the container after all elements have been removed. I'll show you how to write a function that does the job!
#include <algorithm>
#include <string>
void erase_ticks(std::string& s) {
// Returns true for characters that should be removed
auto condition = [](char c) { return c == '`'; };
// Removes characters that match the condition,
// and returns the new endpoint of the string
auto new_end = std::remove_if(s.begin(), s.end(), condition);
// Erases characters from the new endpoint to the current endpoint
s.erase(new_end, s.end());
}
We can use this in main, and it works just as expected!
#include <iostream>
int main() {
std::string s("123`456`789");
std::cout << s << '\n'; // prints 123`456`789
erase_ticks(s);
std::cout << s << '\n'; // prints 123456789
}
This problem has two parts, first we need to identify any characters in the string which we don't want. From your use case it seems that anything that is not numeric needs to go. This is simple enough as the standard library defines a function std::isdigit (simply add the following inclusion "#include <locale>") which takes a character and returns a bool which indicates whether or not the character is numeric.
Second we need a way to quickly and cleanly remove all occurrences of these from the string. Thus we can use the 'Erase Remove' idiom to iterate through the string and do what we want.
string s = "123'4'5";
s.erase(std::remove_if(s.begin(), s.end(), [](char x)->bool {return !std::isdigit(x);}), s.end());
In the snippit above we're calling erase on the string which takes two iterators, the first refers to where we want to begin to delete from and the second tells the call where we want to delete to. The magic in this trick is actually all in the call to remove_if (include "#include <algorithm>" for it). remove_if actually works by shifting the elements (or characters) of string forward to the end of the string.
So "123'4'5'" becomes "12345'''", then it returns an iterator to where it shifted these characters to which is then passed to erase to tell it remove the characters starting here. In the end we're left with "12345" as expected.
Edit: Forgot to mention, remove_if also takes a predicate here I'm using a lambda which takes a character and returns a bool.

Count word frequency using map

This is my first time implementing map in C++. So given a character array with text, I want to count the frequency of each word occurring in the text. I decided to implement map to store the words and compare following words and increment a counter.
Following is the code I have written so far.
const char *kInputText = "\
So given a character array with text, I want to count the frequency of
each word occurring in the text.\n\
I decided to implement map to store the\n\
words and compare following words and increment a counter.\n";
typedef struct WordCounts
{
int wordcount;
}WordCounts;
typedef map<string, int> StoreMap;
//countWord function is to count the total number of words in the text.
void countWord( const char * text, WordCounts & outWordCounts )
{
outWordCounts.wordcount = 0;
size_t i;
if(isalpha(text[0]))
outWordCounts.wordcount++;
for(i=0;i<strlen(text);i++)
{
if((isalpha(text[i])) && (!isalpha(text[i-1])))
outWordCounts.wordcount++;
}
cout<<outWordCounts.wordcount;
}
//count_for_map() is to count the word frequency using map.
void count_for_map(const char *text, StoreMap & words)
{
string st;
while(text >> st)
words[st]++;
}
int main()
{
WordCounts wordCounts;
StoreMap w;
countWord( kInputText, wordCounts );
count_for_map(kInputText, w);
for(StoreMap::iterator p = w.begin();p != w.end();++p)
{
std::cout<<p->first<<"occurred" <<p->second<<"times. \n";
}
return 0;
}
Error: No match for 'operator >>' in 'text >> st'
I understand this is an operator overloading error, so I went ahead and
wrote the following lines of code.
//In the count_for_map()
/*istream & operator >> (istream & input,const char *text)
{
int i;
for(i=0;i<strlen(text);i++)
input >> text[i];
return input;
}*/
Am I implementing map in the wrong way?
There is no overload for >> with a const char* left hand side.
text is a const char*, not an istream, so your overload doesn't apply (and the overload 1: is wrong, and 2: already exists in the standard library).
You want to use the more suitable std::istringstream, like this:
std::istringstream textstream(text);
while(textstream >> st)
words[st]++;
If you use modern C++ language, then life will get by far easier.
First. Usage of a std::map is the correct approach.
This is a more or less standard approach for counting something in a container.
We can use an associative container like a std::map or a std::unordered_map. And here we associate a "key", in this case the "word" to count, with a value, in this case the count of the specific word.
And luckily the maps have a very nice index operator[]. This will look for the given key and if found, return a reference to the value. If not found, the it will create a new entry with the key and return a reference to the new entry. So, in bot cases, we will get a reference to the value used for counting. And then we can simply write:
std::unordered_map<std::string, unsigned int> counter{};
counter[word]++;
But how to get words from a string. A string is like a container containing elements. And in C++ many containers have iterators. And especially for strings there is a dedicated iterator that allows to iterate over patterns in a std::string. It is called std::sregex_token_iterator and described here.. The pattern is given as a std::regex which will give you a great flexibility.
And, because we have such a wonderful and dedicated iterator, we should use it!
Eveything glued together will give a very compact solution, with a minimal number of code lines.
Please see:
#include <iostream>
#include <string>
#include <regex>
#include <map>
#include <iomanip>
const std::regex re{ "\\w+" };
const std::string text{ R"(So given a character array with text, I want to count the frequency of
each word occurring in the text.
I decided to implement map to store the
words and compare following words and increment a counter.")" };
int main() {
std::map<std::string, unsigned int> counter{};
for (auto word{ std::sregex_token_iterator(text.begin(),text.end(),re) }; word != std::sregex_token_iterator(); ++word)
counter[*word]++;
for (const auto& [word, count] : counter)
std::cout << std::setw(20) << word << "\toccurred\t" << count << " times\n";
}

How to order strings case-insensitively (not lexicographically)?

I'm attempting to order a list input from a file alphabetically (not lexicographically). So, if the list were:
C
d
A
b
I need it to become:
A
b
C
d
Not the lexicographic ordering:
A
C
b
d
I'm using string variables to hold the input, so I'm looking for some way to modify the strings I'm comparing to all uppercase or lowercase, or if there's some easier way to force an alphabetic comparison, please impart that wisdom. Thanks!
I should also mention that we are limited to the following libraries for this assignment: iostream, iomanip, fstream, string, as well as C libraries, like cstring, cctype, etc.
It looks like I'm just going to have to defeat this problem via some very tedious method of character extraction and toppering for each string.
Converting the individual strings to upper case and comparing them is not made particularly worse by being restricted from using algorithm, iterator, etc. The comparison logic is about four lines of code. Even though it would be nice not to have to write those four lines having to write a sorting algorithm is far more difficult and tedious. (Well, assuming that the usual C version of toupper is acceptable in the first place.)
Below I show a simple strcasecmp() implementation and then put it to use in a complete program which uses restricted libraries. The implementation of strcasecmp() itself doesn't use restricted libraries.
#include <string>
#include <cctype>
#include <iostream>
void toupper(std::string &s) {
for (char &c : s)
c = std::toupper(c);
}
bool strcasecmp(std::string lhs, std::string rhs) {
toupper(lhs); toupper(rhs);
return lhs < rhs;
}
// restricted libraries used below
#include <algorithm>
#include <iterator>
#include <vector>
// Example usage:
// > ./a.out <<< "C d A b"
// A b C d
int main() {
std::vector<std::string> input;
std::string word;
while(std::cin >> word) {
input.push_back(word);
}
std::sort(std::begin(input), std::end(input), strcasecmp);
std::copy(std::begin(input), std::end(input),
std::ostream_iterator<std::string>(std::cout, " "));
std::cout << '\n';
}
You don't have to modify the strings before sorting. You can sort them in place with a case-insensitive single character comparator and std::sort:
bool case_insensitive_cmp(char lhs, char rhs) {
return ::toupper(static_cast<unsigned char>(lhs) <
::toupper(static_cast<unsigned char>(rhs);
}
std::string input = ....;
std::sort(input.begin(), input.end(), case_insensitive_cmp);
std::vector<string> vec {"A", "a", "lorem", "Z"};
std::sort(vec.begin(),
vec.end(),
[](const string& s1, const string& s2) -> bool {
return strcasecmp(s1.c_str(), s2.c_str()) < 0 ? true : false;
});
Use strcasecmp() as comparison function in qsort().
I am not completely sure how to write it, but what you want to do is convert the strings to lower or uppercase.
If the strings are in an array to begin with, you would run through the list, and save the indexes in order in an (int) array.
If you're just comparing letters, then a terrible hack which will work is to mask the upper two bits off each character. Then upper and lower case letters fall on top of each other.

How to make an iterator to a read-only object writable (in C++)

I've created a unordered_set of my own type of struct. I have an iterator to this set and would like to increment a member (count) of the struct that the iterator points to. However, the compiler complains with the following message:
main.cpp:61:18: error: increment of member ‘SentimentWord::count’ in read-only object
How can I fix this?
Here's my code:
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <string>
#include <unordered_set>
using namespace std;
struct SentimentWord {
string word;
int count;
};
//hash function and equality definition - needed to used unordered_set with type SentimentWord
struct SentimentWordHash {
size_t operator () (const SentimentWord &sw) const;
};
bool operator == (SentimentWord const &lhs, SentimentWord const &rhs);
int main(int argc, char **argv){
ifstream fin;
int totalWords = 0;
unordered_set<SentimentWord, SentimentWordHash> positiveWords;
unordered_set<SentimentWord, SentimentWordHash> negativeWords;
//needed for reading in sentiment words
string line;
SentimentWord temp;
temp.count = 0;
fin.open("positive_words.txt");
while(!fin.eof()){
getline(fin, line);
temp.word = line;
positiveWords.insert(temp);
}
fin.close();
//needed for reading in input file
unordered_set<SentimentWord, SentimentWordHash>::iterator iter;
fin.open("041.html");
while(!fin.eof()){
totalWords++;
fin >> line;
temp.word = line;
iter = positiveWords.find(temp);
if(iter != positiveWords.end()){
iter->count++;
}
}
for(iter = positiveWords.begin(); iter != positiveWords.end(); ++iter){
if(iter->count != 0){
cout << iter->word << endl;
}
}
return 0;
}
size_t SentimentWordHash::operator () (const SentimentWord &sw) const {
return hash<string>()(sw.word);
}
bool operator == (SentimentWord const &lhs, SentimentWord const &rhs){
if(lhs.word.compare(rhs.word) == 0){
return true;
}
return false;
}
Any help is greatly appreciated!
Elements in an unordered_set are, by definition, immutable:
In an unordered_set, the value of an element is at the same time its
key, that identifies it uniquely. Keys are immutable, therefore, the
elements in an unordered_set cannot be modified once in the container
- they can be inserted and removed, though.
I would vote that you use an unordered_map instead, using a string as the key and an int as the mapped value.
One solution (but a dirty hack) is to make your counter mutable, which means, that you permit to change it even on const objects.
struct SentimentWord {
string word;
mutable int count;
};
As I already said, this is a dirty hack, since it allows you to violate rules (you soften them). And rules have a reason. I'm not even sure if this works, since the definition of the unordered_set says that the values can't be modified once being inserted, and this also has a reason.
A nicer solution is to use a map which uses the word as a key and the counter as a value. Your code then doesn't have to use find but simply access the element using the subscript operator ("array access" operator) which directly returns a reference (not an iterator). On this reference, use the increment operator, like this:
std::unordered_map<std::string,int> positiveWords;
//...
positiveWords[word]++;
Then you don't need your struct at all, and of course also not your custom comparison operator overload.
Trick (just in case you need it): If you want to order a map by its value (if you need a statistical map with the most frequent words coming first), use a second (but ordered) map with reversed key and value. This will sort it by the original value, which is now the key. Iterate it in reverse order to start with the most frequent words (or construct it with std::greater<int> as the comparison operator, provided as the third template parameter).
std::unordered_set is unhappy because it's worried you will change the object in such a way it is the same as another object, which would violate the set. ISTM you really want a map from string to int (not a set at all), and the iterator will let you change the returned value, if not the key.

How to reverse an std::string? [duplicate]

This question already has answers here:
How do you reverse a string in place in C or C++?
(21 answers)
Closed 6 years ago.
Im trying to figure out how to reverse the string temp when I have the string read in binary numbers
istream& operator >>(istream& dat1d, binary& b1)
{
string temp;
dat1d >> temp;
}
I'm not sure what you mean by a string that contains binary numbers. But for reversing a string (or any STL-compatible container), you can use std::reverse(). std::reverse() operates in place, so you may want to make a copy of the string first:
#include <algorithm>
#include <iostream>
#include <string>
int main()
{
std::string foo("foo");
std::string copy(foo);
std::cout << foo << '\n' << copy << '\n';
std::reverse(copy.begin(), copy.end());
std::cout << foo << '\n' << copy << '\n';
}
Try
string reversed(temp.rbegin(), temp.rend());
EDIT: Elaborating as requested.
string::rbegin() and string::rend(), which stand for "reverse begin" and "reverse end" respectively, return reverse iterators into the string. These are objects supporting the standard iterator interface (operator* to dereference to an element, i.e. a character of the string, and operator++ to advance to the "next" element), such that rbegin() points to the last character of the string, rend() points to the first one, and advancing the iterator moves it to the previous character (this is what makes it a reverse iterator).
Finally, the constructor we are passing these iterators into is a string constructor of the form:
template <typename Iterator>
string(Iterator first, Iterator last);
which accepts a pair of iterators of any type denoting a range of characters, and initializes the string to that range of characters.