Incrementing characters being read - c++

I am trying to decode an input file that looks something like this:
abbaabbbbaababbaabababaabababaabbababaabababababababa...
and compare it to a makeshift mapping I have made using two arrays
int secretNumber[10];
string coding[10];
coding[0]="abb";
coding[1]="aabbbba";
coding[2]="abab";
...
I am not sure how I can start off by reading the first character which is 'a' then check if it's in the coding array. If it is print out the secretCoding and move the next character b. Else if it's not in the array then add the next character to the first in a string and check to see if "ab" is in the array and if that isn't either add the next character which makes "abb" and so on.
Something like this:
while (!(readFile.eof()) ){
for(int i=0; i<10; i++){
if(stringOfChars==coding[i]){
cout << secretNumber[i] <<endl;
//Now increment to next char
}
else{
//combine the current string with the next character
}
}
}
Question: How do I go about reading in a character if its a match move to next character if not combine current character and the next character until there's a match.

You sould use a design pattern called interpreter.
Here is a link to a c++ version.

If you want a solution that works for arbitrary input sizes, i.e. which doesn't store the entire input in memory, then you can use a queue (e.g. std::deque<char>) to read in a handful of characters at a time, pushing data in from the back. Then you check if the queue still has three, four or five characters left, and if so compare them to your patterns; if there's a match, you pop the corresponding characters off from the front of the queue.

I'm not sure but perhaps it seems like you are trying to implement the LZW compression algorithm. If that is the case, then you would have to change your approach a little. If you have decided that your secret code are integers, then you would have to assign a code to all the elements of the initial contents of the dictionary. The initial dictionary is basically all the strings in your source alphabet of size 1. In your case it would be "a to z", or only "a" and "b" if you are keeping it simple.
The other thing is that you need to look through your dictionary for any existing string which has been assigned a code. The best way to do that is to use STL map container which could map strings to integers in your case. Also, its a good idea to place a restriction on the size to which the dictionary could grow as new strings continue to be added to it.
Overall,
Use std::map< std::string, int > dictionary; as your dictionary for strings such as a, b, aa, ab, aab, etc... and the matching code for it.
The coding[0], coding[1] would not be required as they strings would serve as the key in this dictionary.
The secretNumber[0], secretNumber[1] also would not be needed as the value would for a key would give the secretNumber.
Here is what it may look like:
std::map< std::string, int > dictionary;
int iWordCount = 0;
/*
Initialize the dictionary with the code for strings of length 1 in your source alphabet.
*/
dictionary["a"] = 0;
dictionary["b"] = 1;
iWordCount = 2; // We would be incrementing this as we keep on adding more strings to the dictionary.
std::string newWord = "", existingWord = "";
while (!(readFile.eof()) ){
/*
I'm assuming the next character is read in the variable "ch".
*/
newWord += ch;
if ( dictionary.count(newWord) != 0 ) { // Existing word.
/*
Do something
*/
}
else { // We encountered this word for the first time.
/*
Do something else
*/
}
}

Related

Extracting certain integers from string C++

Good day to all,
I am having a hard time trying to extract desired integers from a string. I am given the following to read in from a file:
itemnameitemnumber price percentmarkup
examples
Gowns-u2285 24.22 37%
TwoB1Ask1-m1275 90.4 1%
What I have been trying to do is get the item number separated from the item name so that I can store the item number as a reference for sorting. As you can see the first example itemnameitemnumber is a clear cut character to digit separation, whereas the next example has numbers within its item name.
I have tried several different approaches, however with certain item names having integers apart of their name is proving to be beyond my experience.
If anyone can help me with this I would be greatly appreciative for their time and knowledge.
Good day,
I don't know, if you have a fixed number of digits for itemnumber, but i am going to assume that you don't.
This is a simple approach; first you have to separate the words of your line. For example, use std::istringstream.
When you have the line split to words, for example by giving its iterators to a vector, or reading it with operator>>, you start to check the first word from backwards, until you find anything that is not one of "0123456789 " (note the whitespace at the end).
After you've done this, you get the iterator about where these digits end (from backwards), and cut your original string, or if you have the opportunity, the already split string. Voilá! You have yourself your item name and item number.
For the record, i am going to do this whole thing, utilising the same technique for the percent markup too, of course with the exception characters being "% ".
#define VALID_DIGITS "0123456789 "
#define VALID_PERCENTAGE "% "
struct ItemData {
std::string Name;
int Count;
double Price;
double PercentMarkup;
};
int ExtractItemData(std::string Line, ItemData & Output) {
std::istringstream Stream( Line );
std::vector<std::string> Words( Stream.begin(), Stream.end() );
if (Words.size() < 3) {
/* somebody gave us a malformed line with less than needed words */
return -1;
}
// Search from backwards, until you do not find anything that is not digits (0-9) or a whitespace
std::size_t StartOfDigits = Words[0].find_last_not_of( VALID_DIGITS );
if (StartOfDigits == std::string::npos) {
/* error; your item name is invalid */
return -2;
}
else {
// Separate the string into 2 parts
Output.Name = Words[0].substr(0, StartOfDigits); // Get the first part
Output.Count = std::stoi( Words[0].substr(StartOfDigits, Words[0].length() - StartOfDigits) );
Output.Price = std::stod( Words[1] );
// Search from backwards, until we do not find anything that is not '%' or ' '
std::size_t StartOfPercent = Words[2].find_last_not_of(VALID_PERCENTAGE);
Output.PercentMarkup = std::stod( Words[2].substr(0, StartOfPercent) );
}
return 0;
}
Code requies includes sstream, vector, string, and cstdint if you do not have size_t defined
Hope the answer was useful.
Best of luck, COlda.
PS.: My first answer on stack overflow ^^;
you can iterate on the string pushing the numbers to a vector then use stringstream to convert them to integers

Trying to read a single character at a time into an array of indefinite size

I am a CS student working on a c++ project. We have been instructed to declare a struct and use it to read in an array of chars and keep a tally of how many letters are used in the string. We are not allowed to use a string; it MUST be an array of our declared struct.
The input must be as long as the user wants; the code has to be able to accept new lines of input and be terminated by '.'
I'm really struggling here. I don't even know where to begin. I've thrown together some code as best-guess for what to do, but it crashes after pressing "." then enter, and I don't know why.
//declare struct
struct data
{
int tally = 0;
char letter;
};
//size of string to read in at a time
const int SIZE_OF_CHUNK = 11;
int main()
{
//input chunk of struct
data input[SIZE_OF_CHUNK];
int placemark,
length;
cout << "Enter sequence of characters, '.' to terminate:" << endl;
do
{
for (int index = 0; (input[index].letter != '\0') && (input[index - 1].letter != '.'); index++)
{
cin >> input[index].letter;
placemark++;
}
//I intend to put something here to handle if the code
needs to read in another chunk, but I want to fix the crashing
problem first
}
while (input[placemark].letter != '.');
//print out what was read in, just to check
for (int index = 0; input[index].letter != '\0'; index++)
{
cout << input[index].letter;
}
return 0;
}
I've tried looking up how to read in a single character but haven't found anything helpful to my circumstances so far. Any tips on what I'm doing wrong, or where I can find helpful resources, would be very much appreciated.
Are you sure you must use a declared struct?
If you just want to count the number of times a character has appeared, you don't need to store the character; you just need to store the number of times it appeared. So just unsigned lettersCount[26], and each index maps to a letter (i.e. index 0 means a, index 1 means b). Whenever a letter appears, just increase the count of that index.
You can map a letter to the index by making use of ASCII. Every letter is represented by a decimal number that you can look it up at ASCII table. For example, the letter a is represented by the decimal value 97, b is 98 and so on. The number increases successively, which we can make use of. So if you want to map a letter to an index, all you need to do is just value - 97 or value - 'a'. For example, if you read in the letter a, take away 97 from that and you'll get 0, which is what you want. After getting the index, it's just a simple ++ to increment the count of that letter.
Regarding the treatment of uppercase and lowercase (i.e. treat them the same or differently), it'll be up to you to figure it out how to do it (which should be fairly simple if you can understand what I've explained).

want to optimize this string manipulation program c++

I've just solve this problem:
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3139
Here's my solution:
https://ideone.com/pl8K3K
int main(void)
{
string s, sub;
int f,e,i;
while(getline(cin, s)){
f=s.find_first_of("[");
while(f< s.size()){
e= s.find_first_of("[]", f+1);
sub = s.substr(f, e-f);
s.erase(f,e-f);
s.insert(0, sub);
f=s.find_first_of("[", f+1);
}
for(i=0; i<s.size(); i++){
while((s[i]==']') || (s[i]=='[')) s.erase(s.begin()+i);
}
cout << s << endl;
}
return 0;
}
I get TLE ,and I wanna know which operation in my code costs too expensive and somehow optimize the code..
Thanks in advance..
If I am reading your problem correctly, you need to rethink your design. There is no need for functions to search, no need for erase, substr, etc.
First, don't think about the [ or ] characters right now. Start out with a blank string and add characters to it from the original string. That is the first thing that speeds up your code. A simple loop is what you should start out with.
Now, while looping, when you actually do encounter those special characters, all you need to do is change the "insertion point" in your output string to either the beginning of the string (in the case of [) or the end of the string (in the case of ]).
So the trick is to not only build a new string as you go along, but also change the point of insertion into the new string. Initially, the point of insertion is at the end of the string, but that will change if you encounter those special characters.
If you are not aware, you can build a string not by just using += or +, but also using the std::string::insert function.
So for example, you always build your output string this way:
out.insert(out.begin() + curInsertionPoint, original_text[i]);
curInsertionPoint++;
The out string is the string you're building, the original_text is the input that you were given. The curInsertionPoint will start out at 0, and will change if you encounter the [ or ] characters. The i is merely a loop index into the original string.
I won't post any more than this, but you should get the idea.

Cannot get second while to loop properly

I'm making a function that removes elements from a string. However, I cant seem to get both of my loops to work together. The first while loop works flawlessly. I looked into it and I believe it might be because when "find_last_of" isn't found, it still returns a value (which is throwing off my loop). I haven't been able to figure out how I can fix it. Thank you.
#include <iostream>
#include <string>
using namespace std;
string foo(string word) {
string compare = "!##$";
string alphabet = "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
while(word.find_first_of(compare) < word.find_first_of(alphabet)) {
int position = word.find_first_of(compare);
word = word.substr(++position);
}
while(word.find_last_of(compare) > word.find_last_of(alphabet)){
int size = word.length();
word = word.substr(0, --size);
}
return word;
}
int main() {
cout << foo("!!hi!!");
return 0;
}
I wrote it like this so compound words would not be affected. Desired result: "hi"
It's not entirely clear what you're trying to do, but how about replacing the second loop with this:
string::size_type p = word.find_last_not_of(compare);
if(p != string::npos)
word = word.substr(0, ++p);
It's not clear if you just want to trim certain characters from the front and back of word or if you want to remove every one of a certain set of characters from word no matter where they are. Based on the first sentence of your question, I'll assume you want to do the latter: remove all characters in compare from word.
A better strategy would be to more directly examine each character to see if it needs to be removed, and if so, do so, all in one pass through word. Since compare is quite short, something like this is probably good enough:
// Rewrite word by removing all characters in compare (and then erasing the
// leftover space, if any, at the end). See std::remove_if() docs.
word.erase(std::remove_if(word.begin(),
word.end(),
// Returns true if a character is to be removed.
[&](const char ch) {
return compare.find(ch) != compare.npos;
}),
word.end());
BTW, I'm not sure why there is both a compare and alphabet string in your example. It seems you would only need to define one or the other, and not both. A character is either one to keep or one to remove.

Pull out data from a file and store it in strings in C++

I have a file which contains records of students in the following format.
Umar|Ejaz|12345|umar#umar.com
Majid|Hussain|12345|majid#majid.com
Ali|Akbar|12345|ali#geeks-inn.com
Mahtab|Maqsood|12345|mahtab#myself.com
Juanid|Asghar|12345|junaid#junaid.com
The data has been stored according to the following format:
firstName|lastName|contactNumber|email
The total number of lines(records) can not exceed the limit 100. In my program, I've defined the following string variables.
#define MAX_SIZE 100
// other code
string firstName[MAX_SIZE];
string lastName[MAX_SIZE];
string contactNumber[MAX_SIZE];
string email[MAX_SIZE];
Now, I want to pull data from the file, and using the delimiter '|', I want to put data in the corresponding strings. I'm using the following strategy to put back data into string variables.
ifstream readFromFile;
readFromFile.open("output.txt");
// other code
int x = 0;
string temp;
while(getline(readFromFile, temp)) {
int charPosition = 0;
while(temp[charPosition] != '|') {
firstName[x] += temp[charPosition];
charPosition++;
}
while(temp[charPosition] != '|') {
lastName[x] += temp[charPosition];
charPosition++;
}
while(temp[charPosition] != '|') {
contactNumber[x] += temp[charPosition];
charPosition++;
}
while(temp[charPosition] != endl) {
email[x] += temp[charPosition];
charPosition++;
}
x++;
}
Is it necessary to attach null character '\0' at the end of each string? And if I do not attach, will it create problems when I will be actually implementing those string variables in my program. I'm a new to C++, and I've come up with this solution. If anybody has better technique, he is surely welcome.
Edit: Also I can't compare a char(acter) with endl, how can I?
Edit: The code that I've written isn't working. It gives me following error.
Segmentation fault (core dumped)
Note: I can only use .txt file. A .csv file can't be used.
There are many techniques to do this. I suggest searching StackOveflow for "[C++] read file" to see some more methods.
Find and Substring
You could use the std::string::find method to find the delimiter and then use std::string::substr to return a substring between the position and the delimiter.
std::string::size_type position = 0;
positition = temp.find('|');
if (position != std::string::npos)
{
firstName[x] = temp.substr(0, position);
}
If you don't terminate a a C-style string with a null character there is no way to determine where the string ends. Thus, you'll need to terminate the strings.
I would personally read the data into std::string objects:
std::string first, last, etc;
while (std::getline(readFromFile, first, '|')
&& std::getline(readFromFile, last, '|')
&& std::getline(readFromFile, etc)) {
// do something with the input
}
std::endl is a manipulator implemented as a function template. You can't compare a char with that. There is also hardly ever a reason to use std::endl because it flushes the stream after adding a newline which makes writing really slow. You probably meant to compare to a newline character, i.e., to '\n'. However, since you read the string with std::getline() the line break character will already be removed! You need to make sure you don't access more than temp.size() characters otherwise.
Your record also contains arrays of strings rather than arrays of characters and you assign individual chars to them. You either wanted to yse char something[SIZE] or you'd store strings!