Implementing an alphabet in C++ - c++

I'm making a code for cipher that reads alphabet in it's binary code. Is there a way to implement custom alphabet (not using ASCII)? For example alphabet={a,b,c,d,e,...,z,],[,.,..., ,-} and for each character there's a number 0,1,...,63. So, the bijetion will be from element of alphabet to 6 bit number.
How to make this implementation using simple functions in C++? I tried to make a strings length 1 and corresponding number using if statements and then plug them into .txt file, but it didn't work out.
string str1, ..., str63;
string sometext;
str1 = 'a';
// ...
cin >> sometext;
int k;
k = sometext.length();
string res;
ofstream out;
out.open("cipher.txt");
for (int i = 0; i < k; i++) {
res = sometext.substr(i, 1);
if (res == str1) {
res = '000000';
}
// ...
if (res == str63) {
res = '111111';
}
out << res;
}

I made a simple class Alphabet achieving your task. It uses std::unordered_map to store mapping between characters and binary representation, and uses this mapping to convert between those two representations. Also it computes binary representation. Class can be given any alphabet.
For testing I do two conversions between char and binary and output results to console. If requested values are out of range then std::exception is thrown.
Try it online!
#include <string>
#include <unordered_map>
#include <cmath>
#include <stdexcept>
#include <iostream>
class Alphabet {
public:
Alphabet(std::string const & _chars)
: chars(_chars) {
size_t num_bits = std::ceil(std::log(std::max(size_t(1), chars.size()))
/ std::log(2) - 1e-6);
for (size_t i = 0; i < chars.size(); ++i) {
std::string bin;
for (ptrdiff_t j = num_bits - 1; j >= 0; --j)
bin += i & (1 << j) ? "1" : "0";
c2b[chars[i]] = bin;
b2c[bin] = chars[i];
}
}
std::string ToBin(char c) const {
auto it = c2b.find(c);
if (it == c2b.end())
throw std::runtime_error("Character '" +
std::string(1, c) + "' not in alphabet!");
return it->second;
}
char ToChar(std::string const & bin) const {
auto it = b2c.find(bin);
if (it == b2c.end())
throw std::runtime_error("Binary '" + bin + "' is out of range!");
return it->second;
}
std::string const & Chars() const {
return chars;
}
private:
std::string chars;
std::unordered_map<char, std::string> c2b;
std::unordered_map<std::string, char> b2c;
};
int main() {
try {
Alphabet alph("abcdef{}123");
std::cout << alph.ToBin('f') << std::endl;
std::cout << alph.ToChar("0011") << std::endl;
std::cout << alph.Chars() << std::endl;
return 0;
} catch (std::exception const & ex) {
std::cout << "Exception: " << ex.what() << std::endl;
return -1;
}
}
Output:
0101
d
abcdef{}123

Related

Can I create constexpr strings with functions?

I have a method that creates a file header with a given comment symbol, depending on the output file type. There are only a few supported file types, thus I want to create these headers at compile time. Can I make these as a constexpr ?
std::string create_header(const std::string &comment_symbol) {
std::string div(15, '-');
std::string space(2, ' ');
std::stringstream hdr;
hdr << comment_symbol << space << " Begin of File." << std::endl;
hdr << comment_symbol << space << div << std::endl;
return hdr.str();
}
std::string c_header() { return create_header("//"); }
std::string python_header() { return create_header("#");
Can I create constexpr strings with functions?
You can't return std::string, cause it allocates memory.
Can I make these as a constexpr ?
Sure, something along:
#include <array>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
template<size_t N> constexpr
auto create_header(const char (&comment_symbol)[N]) {
const char one[] = " Begin of File.\n";
const char two[] = " -\n";
std::array<char,
N + (sizeof(one) - 1) +
N + (sizeof(two) - 1) + 1
> ret{};
auto it = ret.begin();
for (const char *i = comment_symbol; *i; ++i) *it++ = *i;
for (const char *i = one; *i; ++i) *it++ = *i;
for (const char *i = comment_symbol; *i; ++i) *it++ = *i;
for (const char *i = two; *i; ++i) *it++ = *i;
return ret;
}
std::string c_header() {
constexpr auto a = create_header("//");
return std::string{a.begin(), a.end()};
}
int main() {
std::cout << c_header() << '\n';
}

C++ How to write a code that counts top words while removing any special characters from text file

How do I take a text file from the command line that opens and reads it, and then count the top words in that file but also removes any special characters. I have this code done here and used maps but it isn't counting every word. For instance "hello." is one word and also "$#%hello<>?/". I have this file from the song shake it off that's supposed to read shake 78 times but I only counted 26 in this code.
#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <vector>
using namespace std;
string ask(const string& msg) {
string ans;
cout << msg;
getline(cin, ans);
return ans;
}
int main() {
ifstream fin( ask("Enter file name: ").c_str() ) ;
if (fin.fail()) {
cerr << "ERROR"; // this is if the file fails to open
return 1;
}
map<string, int> wordCount;
string entity;
while (fin >> entity) {
vector<string> words;
for (int i = 0, a = 0; i < entity.length(); i++) {
char& c = entity[i];
if (c < 'A' || (c > 'Z' && c < 'a') || c > 'z') {
string word = entity.substr(a, i - a);
a = i + 1;
if (word.length() > 0)
words.push_back(word);
}
}
for (auto & word : words)
wordCount[word]++;
}
fin.close();
vector<string> topWords;
const size_t MAX_WORDS = 10;
for ( auto iter = wordCount.begin(); iter != wordCount.end(); iter ++ ) {
int som = 0, lim = topWords.size();
while (som < lim) {
int i = ( som + lim ) / 2;
int count = wordCount[topWords[i]];
if ( iter -> second > count)
lim = i;
else if ( iter -> second < count )
som = i + 1;
else
som = lim = i;
}
if (som < MAX_WORDS ) {
topWords.insert( topWords.begin() + som, iter -> first );
if ( topWords.size() > MAX_WORDS )
topWords.pop_back();
}
}
for (auto & topWord : topWords)
cout << "(" << wordCount[topWord] << ")\t" << topWord << endl;
return 0;
}
One last thing if yall can probably help me on is how would I also write a code that takes a number from the command line alongside the filename and with that number, display the number of top words corresponding with that number passed in the command line, I would assume there is a parse args involved maybe.
Thank you again!
https://s3.amazonaws.com/mimirplatform.production/files/48a9fa64-cddc-4e45-817f-3e16bd7772c2/shake_it_off.txt
!hi!
#hi#
#hi#
$hi$
%hi%
^hi^
&hi&
*hi*
(hi(
)hi)
_hi_
-hi-
+hi+
=hi=
~hi~
`hi`
:hi:
;hi;
'hi'
"hi"
<hi<
>hi>
/hi/
?hi?
{hi{
}hi}
[hi[
]hi]
|hi|
\hi\
bob bob bob bob bob bob bob !###$$%#&#^*()#*#)_++(#<><#:":bob###$$%#&#^*()#*#)_++(#<><#:":
!###$$%#&#^*()#*#)_++(#<><#:":bob###$$%#&#^*()#*#)_++(#<><#:": !###$$%#&#^*()#*#)_++(#<><#:":bob###$$%#&#^*()#*#)_++(#<><#:":
!###$$%#&#^*()#*#)_++(#<><#:":bob###$$%#&#^*()#*#)_++(#<><#:": !###$$%#&#^*()#*#)_++(#<><#:":bob###$$%#&#^*()#*#)_++(#<><#:
this is the special character test
Your original code is somewhat hard to refine, I have followed your description to get a program that uses STL.
Combine erase with remove_if to remove unwanted chars
Use set to resort by counts
If you have some experience with Boost, it's a use case with multimap or bimap, which can make the code even more cleaner.
#include <algorithm>
#include <fstream>
#include <iostream>
#include <map>
#include <set>
#include <string>
#include <vector>
using namespace std;
string ask(const string& msg) {
string ans;
cout << msg;
getline(cin, ans);
return ans;
}
int main() {
// ifstream fin(ask("Enter file name: ").c_str());
ifstream fin("shake_it_off.txt");
if (fin.fail()) {
cerr << "ERROR"; // this is if the file fails to open
return 1;
}
map<string, size_t> wordCount;
string entity;
while (fin >> entity) {
entity.erase(std::remove_if(entity.begin(), entity.end(),
[](char ch) { return !isalpha(ch); }),
entity.end());
wordCount[entity] += 1;
}
auto cmp = [](const std::pair<std::string, size_t>& lhs,
const std::pair<std::string, size_t>& rhs) {
return lhs.second > rhs.second;
};
std::multiset<std::pair<std::string, size_t>, decltype(cmp)> top(
wordCount.begin(), wordCount.end(), cmp);
auto it = top.begin();
const size_t MAX_WORDS = 10;
for (size_t i = 0; i < MAX_WORDS && it != top.end(); ++i, ++it) {
cout << "(" << it->first << ")\t" << it->second << endl;
}
return 0;
}

Replace a loop to retrieve the index of the first element in an array

Is there a better way to search for the index of the first element using a predicate?
// ... this code looks a bit long to me. Anyway to do better?
auto it = std::find_if(collection + startAt,
collection + COLLECTION_SIZE,
[](const char* line) { return strlen(line) <= 10; });
int idx = std::dist(collection, it); //= it - collection;
This is my attempt to refactor the C-style code below:
for (posEmptyItem = startAt; strlen(collection[posEmptyItem]) > 10; posEmptyItem++) {}
std::cout << posEmptyItem << std::endl;
Here a complete example of
#include "stdafx.h"
#include <cstring>
#include <iostream>
#include <algorithm>
#define COLLECTION_SIZE 123
int main()
{
char* collection[COLLECTION_SIZE]{ "time11,time2,time3",
"time12,time2,time3",
"time13,time2,time3",
"time14,time2,time3",
"time15,time2,time3",
"x\n",
"" };
auto startAt = 2;
int posEmptyItem;
// legacy code
for (posEmptyItem = startAt; strlen(collection[posEmptyItem]) > 10; posEmptyItem++) {}
std::cout << posEmptyItem << std::endl;
// replace the loop to search an index by calling to standard library
auto it = std::find_if(collection + startAt,
collection + COLLECTION_SIZE,
[](const char* line) { return strlen(line) <= 10; });
posEmptyItem = it - collection;
std::cout << posEmptyItem << std::endl;
return 0;
}

Python C++: is the any python.split() like method in c++? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I tokenize a string in C++?
Splitting a string in C++
Is there any python.split(",") like method in C++ please.
Got the following code from some where .. might help
#define MAIN 1
#include <string>
#include <vector>
#include <iostream>
using namespace std;
class splitstring : public string {
vector<string> flds;
public:
splitstring(char *s) : string(s) { };
vector<string>& split(char delim, int rep=0);
};
vector<string>& splitstring::split(char delim, int rep) {
if (!flds.empty()) flds.clear();
string work = data();
string buf = "";
int i = 0;
while (i < work.length()) {
if (work[i] != delim)
buf += work[i];
else if (rep == 1) {
flds.push_back(buf);
buf = "";
} else if (buf.length() > 0) {
flds.push_back(buf);
buf = "";
}
i++;
}
if (!buf.empty())
flds.push_back(buf);
return flds;
}
#ifdef MAIN
main()
{
splitstring s("Humpty Dumpty sat on a wall. Humpty Dumpty had a great fall");
cout << s << endl;
vector<string> flds = s.split(' ');
for (int k = 0; k < flds.size(); k++)
cout << k << " => " << flds[k] << endl;
cout << endl << "with repeated delimiters:" << endl;
vector<string> flds2 = s.split(' ', 1);
for (int k = 0; k < flds2.size(); k++)
cout << k << " => " << flds2[k] << endl;
}
#endif
In boost:
vector<string> results;
boost::split(results, line, boost::is_any_of("#"));
In STL:
template <typename E, typename C>
size_t split(std::basic_string<E> const& s, C &container,
E const delimiter, bool keepBlankFields = true) {
size_t n = 0;
std::basic_string<E>::const_iterator it = s.begin(), end = s.end(), first;
for (first = it; it != end; ++it) {
if (delimiter == *it) {
if (keepBlankFields || first != it) {
container.push_back(std::basic_string<E > (first, it));
++n;
first = it + 1;
} else ++first;
}
}
if (keepBlankFields || first != it) {
container.push_back(std::basic_string<E > (first, it));
++n;
}
return n;
}

Multiplying a string by an int in C++

What do I have to do so that when I
string s = ".";
If I do
cout << s * 2;
Will it be the same as
cout << "..";
?
std::string has a constructor of the form
std::string(size_type count, char c);
that will repeat the character. For example
#include <iostream>
int main() {
std::string stuff(2, '.');
std::cout << stuff << std::endl;
return 0;
}
will output
..
I used operator overloading to simulate this behavior in c++.
#include <iostream>
#include <string>
using namespace std;
/* Overloading * operator */
string operator * (string a, unsigned int b) {
string output = "";
while (b--) {
output += a;
}
return output;
}
int main() {
string str = "abc";
cout << (str * 2);
return 0;
}
Output:
abcabc
No, std::string has no operator *. You can add (char, string) to other string. Look at this http://en.cppreference.com/w/cpp/string/basic_string
And if you want this behaviour (no advice this) you can use something like this
#include <iostream>
#include <string>
template<typename Char, typename Traits, typename Allocator>
std::basic_string<Char, Traits, Allocator> operator *
(const std::basic_string<Char, Traits, Allocator> s, size_t n)
{
std::basic_string<Char, Traits, Allocator> tmp = s;
for (size_t i = 0; i < n; ++i)
{
tmp += s;
}
return tmp;
}
template<typename Char, typename Traits, typename Allocator>
std::basic_string<Char, Traits, Allocator> operator *
(size_t n, const std::basic_string<Char, Traits, Allocator>& s)
{
return s * n;
}
int main()
{
std::string s = "a";
std::cout << s * 5 << std::endl;
std::cout << 5 * s << std::endl;
std::wstring ws = L"a";
std::wcout << ws * 5 << std::endl;
std::wcout << 5 * ws << std::endl;
}
http://liveworkspace.org/code/52f7877b88cd0fba4622fab885907313
There is no predefined * operator that will multiply a string by an int, but you can define your own:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
string operator*(const string& s, unsigned int n) {
stringstream out;
while (n--)
out << s;
return out.str();
}
string operator*(unsigned int n, const string& s) { return s * n; }
int main(int, char **) {
string s = ".";
cout << s * 3 << endl;
cout << 3 * s << endl;
}
They can't be multipled but I think you can write your own function to do this, something like -
#include <iostream>
#include <string>
std::string operator*(std::string s, size_t count)
{
std::string ret;
for(size_t i = 0; i < count; ++i)
{
ret = ret + s;
}
return ret;
}
int main()
{
std::string data = "+";
std::cout << data * 10 << "\n";
}
It's probably not the best idea though, it will be very confusing to anyone looking at the code and not expecting this,
Strings cannot be multiplied.
If s is a char
'.' // This has ASCII code 46
then
cout << (char)((int)s * 2);
will give you
'/' // This has ASCII code 92
Like JRG did, but in a single line
std::cout << std::string(70,'-') << std::endl;
This will create a string, filled with - (dashes), 70 characters long, and breaking the line at the end with std::endl;
You can do this:
#include <iostream>
using namespace std;
int main()
{
string text, new_text;
int multiply_number;
cin >> text >> multiply_number;
/*
First time in the 'for' loop: new_text = new_text + text
new_text = "" + "your text"
new_text = "your text"
Second time in the 'for' loop: new_text = new_text + text
new_text = "your text" + "your text"
new_text = "your textyour text"...n times
*/
for(int i=0; i<multiply_number; i++)
{
new_text += text;
}
cout << new_text << endl; // endl="\n"
system("pause");
return 0;
}
In Python you can multiply string like this:
text = "(Your text)"
print(text*200)
std::string StrMultiply(const char* str, size_t count) {
size_t stringsize = strlen(str);
size_t buffersize = stringsize * count + 1;
string res(buffersize,'\0');
char* end = res._Unchecked_end();
char* offset = res._Unchecked_begin();
for (size_t i = 0;i < count; offset += stringsize,i++)
{
memcpy(offset, str, stringsize);
}
// mark the end
res[buffersize - 1] = '\0';
return res;
}
inline std::string operator*(std::string left, size_t right) {
return StrMultiply(left.c_str(), right);
}
here is a ram-friendly solution, 10 times faster than using stringstreams or string::append
It's surprising that nobody talked about this yet. For assigning char*int to a variable, you can do str.assign(n, char). https://en.cppreference.com/w/cpp/string/basic_string/assign
For example, str.assign(2, 's') would yield ss for the value of str. Other methods to actually achieve the objective have already been mentioned.