Ok, so I'm working on a project that requires us to translate English to Pig Latin. I was trying to kind of copy and tweak some code I found online that did the opposite because the functions kind of looked similar. In my class, we are given certain functions that have to be implemented in our code.
This has to be present in my source code:
struct Word
{
string english;
string pigLatin;
};
Function 1: Word * splitSentence(const string words, int &size); ~ Takes the English sentence as 1 string
Function 2: void convertToPigLatin(Word [] wordArr, int size); ~ Converts English to Pig Latin
Function 3: void convertToPigLatin(Word [] wordArr, int size); ~ Display
Here is the code that I have.
Edit: The problem I'm having is that I don't have wordArr declared anywhere in my code so it can't compile. I also noticed a few minor errors and changed my code a little. You'll have to excuse me I'm very tired right now.
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
struct Word
{
string english;
string pigLatin;
};
Word * splitSentence(wordArr&; int &);
void convertToPigLatin (Word[], int);
void displayPigLatin (Word[], int);
int main()
{
string userInput;
int size;
cout <<"This is an English to Pig Latin translator.\n";
cout <<"Enter a sentance that you want to translate.\n";
getline(cin, userInput);
Word *wordArr = convertToPigLatin(userInput, size);
displayPigLatin(wordArr, size);
return 0;
}
Word * splitSentence(const Word [] wordArr, int &size)
{
int num = 0;
int phraseLength = userInput.length();
for (int i = 0; i < size; i++)
{
if (isspace(userInput[i]))
{
if (isspace(userInput[ i - 1]))
{
num--;
}
num++;
}
}
if (ispunct(userInput[i]))
{
if (i != (phraseLength - 1))
{
userInput.erase(1--, 1)
}
}
}
void convertToPigLatin(Word wordArr[], int size)
{
for (int i = 0; i < size; i++)
{
int stringLength;
if (i == (size - 1))
{
stringLength = wordArr[i].userInput.length();
}
else
{
stringLength = wordArr[i].userInput.length() - 1;
}
string vowel, way;
vowel = wordArr[i].userInput.at(stringLength - stringLength);
way = wordArr[i].userInput.at(stringLength - 3);
bool markV = ((vowel == 'A') || (vowel == 'a') (vowel == 'E') || (vowel == 'e')
(vowel == 'I') || (vowel == 'i') (vowel == 'O') || (vowel == 'o')
(vowel == 'U') || (vowel == 'u'));
wordArr[i].userInput.erase(stringLength - 3, 3);
if (!(markV && (way == 'w')))
{
wordArr[i].english = way + wordArr[i].userInput;
}
}
displayPigLatin(wordArr, stringLength);
}
void displayPigLatin(const Word wordArr[], int size);
{
cout << "\nHere is your phrase in PigLatin: ";
for (int i = 0 i < size; i++)
{
cout << wordArr[i].userInput << " ";
}
}
Important Note: You can only use range based for-loops in C++11 or higher if your compiler doesn't support C++11 or higher, use regular for-loops...
Given your question, you have to use this structure (It is equivalent to the one in the question):
typedef struct
{
std::string english;
std::string pig_latin;
} Word;
This is a macro which is going to be used to check if the first letter is a vowel or a consonant (Hence, !IS_VOWEL(some_char))...
#define IS_VOWEL(x) ((x) == 'A' || (x) == 'E' || (x) == 'I' || (x) == 'O' || (x) == 'U' || \
(x) == 'a' || (x) == 'e' || (x) == 'i' || (x) == 'o' || (x) == 'u')
Another function which we need to acquire only the part of the word which has letters (not symbols and numbers):
std::pair<unsigned, unsigned> GetWord(std::string word)
{
auto start = word.end();
for (auto it = word.begin(); it != word.end(); ++it)
if (tolower(*it) >= 'a' && tolower(*it) <= 'z' && start == word.end())
start = it;
else if (start != word.end() && !(tolower(*it) >= 'a' && tolower(*it) <= 'z'))
return std::make_pair(std::distance(word.begin(), start), std::distance(word.begin(), it));
return std::make_pair(start == word.end() ? 0 : std::distance(word.begin(), start), std::distance(word.begin(), word.end()));
}
And last but not least, the function to convert English to Pig-Latin (I know it is huge):
std::vector<Word> CreatePigLatinWordsFromEnglish(std::string english, bool sentence_case = true)
{
// You can break it from here to use inside another function (viz., splitSentence)
std::transform(english.begin(), english.end(), english.begin(), ::tolower);
std::stringstream english_stream(english);
std::vector<Word> words;
std::string temporary;
while (std::getline(english_stream, temporary, ' '))
words.emplace_back(Word({ temporary, "" }));
// Till here...
// From here the conversion starts...
for (auto &word : words)
{
auto const word_it = GetWord(word.english);
if (!IS_VOWEL(word.english[word_it.first]) && !std::string(std::next(word.english.begin(), word_it.first),
std::next(word.english.begin(), word_it.second)).empty())
{
word.pig_latin.append(std::string(word.english.begin(), std::next(word.english.begin(), word_it.first)));
word.pig_latin.append(std::string(std::next(word.english.begin(), word_it.first + 1), std::next(word.english.begin(), word_it.second)));
word.pig_latin.append(1, word.english[word_it.first]);
word.pig_latin.append(std::string("ay"));
word.pig_latin.append(std::next(word.english.begin(), word_it.second), word.english.end());
}
else
word.pig_latin = std::string(word.english.begin(), std::next(word.english.begin(), word_it.second)) + "way"
+ std::string(std::next(word.english.begin(), word_it.second), word.english.end());
}
// Conversion ends here...
// Changing the case from lower case to sentence case if needed...
if (sentence_case)
{
words[0].english[0] = toupper(words[0].english[0]);
words[0].pig_latin[0] = toupper(words[0].pig_latin[0]);
}
return words; // Returning the list of words we got...
}
Well, an example to demonstrate this method:
int main()
{
auto const test = "An apple a day keeps the doctor away!";
for (auto word : CreatePigLatinWordsFromEnglish(test))
std::cout << word.pig_latin << " ";
return 0;
}
Output:
Anway appleway away ayday eepskay hetay octorday awayway!
Try it out and see whether it gives you the required result...
Kind regards,
Ruks.
Related
I want to iterate char by char in a vector of strings. In my code I created a nested loop to iterate over the string, but somehow I get an out of range vector.
void splitVowFromCons(std::vector<std::string>& userData, std::vector<std::string>& allCons, std::vector<std::string>& allVows){
for ( int q = 0; q < userData.size(); q++){
std::string userDataCheck = userData.at(q);
for ( int r = 0; r < userDataCheck.size(); r++){
if ((userDataCheck.at(r) == 'a') || (userDataCheck.at(r) == 'A') || (userDataCheck.at(r) == 'e') || (userDataCheck.at(r) == 'E') || (userDataCheck.at(r) == 'i') || (userDataCheck.at(r) == 'I') || (userDataCheck.at(r) == 'o') || (userDataCheck.at(r) == 'O') || (userDataCheck.at(r) == 'u') || (userDataCheck.at(r) == 'U')){
allVows.push_back(userData.at(r));
}
else if ((userDataCheck.at(r) >= 'A' && userDataCheck.at(r) <= 'Z') || (userDataCheck.at(r) >= 'a' && userDataCheck.at(r) <= 'z')){
allCons.push_back(userData.at(r));
}
else {
continue;;
}
}
}
}
The error here is in these lines:
allVows.push_back(userData.at(r));
allCons.push_back(userData.at(r));
the r variable is your index into the current string, but here you're using it to index into the vector, which looks like a typo to me. You can make this less error prone using range-for loops:
for (const std::string& str : userData) {
for (char c : str) {
if (c == 'a' || c == 'A' || ...) {
allVows.push_back(c);
}
else if (...) {
....
}
}
}
which I hope you'll agree also has the benefit of being more readable due to less noise. You can further simplify your checks with a few standard library functions:
for (const std::string& str : userData) {
for (char c : str) {
if (!std::isalpha(c)) continue; // skip non-alphabetical
char cap = std::toupper(c); // capitalise the char
if (cap == 'A' || cap == 'E' || cap == 'I' || cap == 'O' || cap == 'U') {
allVows.push_back(c);
}
else {
allCons.push_back(c);
}
}
}
Since this question is about debugging actually, I think it is a nice illustration of how the usage of std::algorithms of C++ can decrease the effort needed to see what is wrong with a non working code.
Here is how it can be restructured:
bool isVowel(char letter)
{
return letter == 'A' || letter == 'a' ||
letter == 'E' || letter == 'e'||
letter == 'O' || letter == 'o'||
letter == 'Y' || letter == 'y'||
letter == 'U' || letter == 'u';
}
bool isConsonant(char letter)
{
return std::isalpha(letter) && !isVowel(letter);
}
void categorizeLetters(const std::vector<std::string> &words, std::vector<char> &vowels, std::vector<char> &consonants)
{
for( const std::string &word : words){
std::copy_if(word.begin(), word.end(), std::back_inserter(vowels), isVowel);
std::copy_if(word.begin(), word.end(), std::back_inserter(consonants), isConsonant);
}
}
With a solution like this, you avoid the error-prone access-with-index that lead to your problem. Also, code is readable and comprehensive
I got an error on second if
Making the exactly same if outside of for seems to work just fine, it returns the value from priority function, but when I try to do it in for it said that I'm trying to pass an invalid parameter to a function which considers it to be fatal.
#include <iostream>
#include <stack>
#include <string>
using namespace std;
int priority(char c);
int main()
{
stack<char>Operator;
string input;
string output;
getline(cin, input);
for (int i = 0; i < input.size(); i++)
{
if (input[i] == '(' || input[i] == ')' || input[i] == '+' || input[i] == '-' || input[i] == '*' || input[i] == '/')
Operator.push(input[i]);
else
output.push_back(input[i]);
if (priority(Operator.top()) == 3)
{
int aux = Operator.top();
Operator.pop();
while (priority(Operator.top() == 4))
{
output.push_back((char)Operator.top());
Operator.pop();
}
Operator.push(aux);
}
if (priority(Operator.top() == 2))
{
Operator.pop();
while (priority(Operator.top()) != 1)
{
output.push_back(Operator.top());
Operator.pop();
}
Operator.pop();
}
}
cout << output;
cin.ignore();
cin.get();
return 0;
}
int priority(char c)
{
if (c == '(')
return 1;
if (c == ')')
return 2;
if (c == '+' || c == '-')
return 3;
if (c == '*' || c == '/')
return 4;
}
The statement Operator.top() is being called on every symbol in the input string. That would probably work in case your string starts with a '(' symbol or with a unary plus, but what would happen in case of "2*2"?
As a perfect solution you should redesign your code to make it a finit automaton. As a simple ad hoc fix you should check if the current symbol is an operation or digit and don't call the Operator.top() in the latter case:
if (isdigit(input[i])) {
output.push_back(input[i]);
}
else {
Operator.push(input[i]);
if (priority(Operator.top()) == 3) {
// ...
}
// ...
}
Im trying to eliminate just the vowels from my dynamic array.
with this function i just get blank spaces like this.
char* eliminarVocales(char* arreglo, int*size)
{
if (arreglo != nullptr)
{
for (int i = 0; i < *size; i++)
{
if (arreglo[i] == 'a' || arreglo[i] == 'e' || arreglo[i] == 'i' || arreglo[i] == 'o' || arreglo[i] == 'u')
{
arreglo[i] = NULL;
}
}
return arreglo;
}
}
Your program is not removing the vowels, but instead it is replacing their values by "NULL". So in the main function where you are calling this function. You have to write another function (e.g., display function) where you have to display only those values where the value!=NULL.
for(i=0;i>maxvalue;i++)
{
if(arreglo[i] != NULL)
{
cout<<"[i]"<<arreglo[i]<<endl;
}
}
Let me know if it helped u.
You are getting blanks because you are not actually removing any characters from your array, you are just replacing them will nulls, and then not ignoring the nulls when outputting the contents of the array.
Instead of doing the removal manually, consider using the standard std::remove_if() algorithm, which can move any vowels to the end of the array. And since you are passing the array size by pointer, you can modify its value to indicate the new size of the array minus any moved vowels.
For example:
#include <algorithm>
#include <cctype>
char* eliminarVocales(char* arreglo, int* size)
{
if (arreglo)
{
*size = std::distance(
arreglo,
std::remove_if(arreglo, arreglo + *size,
[](int ch){ ch = std::toupper(ch); return ((ch == 'A') || (ch == 'E') || (ch == 'I') || (ch == 'O') || (ch == 'U')); }
)
);
}
return arreglo;
}
Then you can use it like this:
void listarElementos(char* arreglo, int size)
{
for(int i = 0; i < size; ++i)
std::cout << "[" << i << "] : " << arreglo[i] << std::endl;
}
...
#include <cstring>
int size = 5;
char *arreglo = new char[size];
std::strcpyn(arreglo, "hello", 5);
...
listarElementos(arreglo, size); // shows "hello"
...
eliminarVocales(arreglo, &size);
...
listarElementos(arreglo, size); // shows "hll"
...
delete[] arreglo;
If you use a std::vector (or std::string) for your character array, you can then use the erase-remove idiom:
#include <algorithm>
#include <vector>
void eliminarVocales(std::vector<char> &arreglo)
{
arreglo.erase(
std::remove_if(arreglo.begin(), arreglo.end(),
[](int ch){ ch = std::toupper(ch); return ((ch == 'A') || (ch == 'E') || (ch == 'I') || (ch == 'O') || (ch == 'U')); }
),
arreglo.end()
);
}
void listarElementos(const std::vector<char> &arreglo)
{
for(std::size_t i = 0; i < arreglo.size(); ++i)
std::cout << "[" << i << "] : " << arreglo[i] << std::endl;
}
...
#include <cstring>
std::vector<char> arreglo(5);
std::strcpyn(arr.data(), "hello", 5);
...
listarElementos(arreglo); // shows "hello"
...
eliminarVocales(arreglo);
...
listarElementos(arreglo); // shows "hll"
...
I can't get the right output.. please help me..
and it should return false when I put number as the first character for the name
like this ,
Enter the name of the first rectangle: rec 1a
Invalid input. Type 'rec' following by the name or 'stop' if done.
Try again! Enter the name of the first rectangle: rec a
Enter a's bottom left x and y coords: 9 3
Enter a's length and height: 2 8
i am only allow to use these 3, not anything else..
#include <iostream>
#include <string>
#include <vector>
and my code is
bool promptread_rec(const string & prompt, const string & invalid, const string & usedname, string & input, vector<Rectangle> & list)
{
cout << prompt;
getline(cin, input);
if (input == "stop")
{
return true;
}
else if (input.substr(0,4) != "rec ")
{
cout << invalid << endl;
return false;
}
else if (input[4] == '0' || input [4] == '1' || ......)
{
cout << invalid << endl;
return false;
}
else if (list.size() > 0)
{
for (int i = 0; i < list.size(); i++)
{
if (input == list[i].getName())
{
cout << usedname;
return false;
}
}
return true;
}
else
{
return true;
}
}
is there a faster way to do it?? need to avoid all numbers e.g. 0,1,2,3,...,9
From the header cctype, you may use the function isalpha(c) on the first character of the string, like:
string a = "a1234";
assert(isalpha(a.at(0)) == true);
a = "1234";
assert(isalpha(a.at(0)) == true);
Just remember to access a.at(0) only if the string is not empty or else it will throw a std::out_of_range exception
References:
http://www.cplusplus.com/reference/cctype/isalpha/
http://www.cplusplus.com/reference/cassert/assert/
http://www.cplusplus.com/reference/string/string/at/
Since you cannot use any other headers you have to implement your own functions, which is actually simple enough for ASCII characters:
bool IsLetter(char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
bool IsDigit(char c) {
return c >= '0' && c <= '9';
}
Using these two helper functions you can write a function to test if a name is valid:
bool IsValidName(const std::string &name);
I leave this for you to implement.
I attended a quiz, I gave the code but the auto-test shows that one of the eight test cases failed.
I myself tested my code many times, but all passed. I can't find where is the problem.
The question is to design a algorithm to check whether the brackets in a string match.
1) Just consider rounded brackets () and square brackets [], omit ohter chars.
2) Each pair brackets should match each other. That means ( matches ), and [ matches ].
3) Intercrossing is not allowed, such as : ([)]. There are two pairs of brackets, but they intercross each other.
To solve the problem, my method is described as follows:
Search each char in the whole input string, the index from 0 to str.size() - 1.
Use two stacks to record the opening tag (, and [, each type in one stack. When encountering one of them, push its index in the corresponding stack.
When encouterning the closing tag ) and ], we pop the corresponding stack.
Before popping, check the top of two stacks, the current stack should have the max index, otherwise that means there are unmatched opening tag with the other type, so the intercrossing can be checked this way.
My Code is Here:
#include <iostream>
#include <stack>
using namespace std;
int main()
{
string str;
cin >> str;
stack<int> s1, s2;
int result = 0;
for (int ix = 0, len = str.size(); ix < len; ix++)
{
if (str[ix] == '(')
{
s1.push(ix);
}
else if (str[ix] == '[')
{
s2.push(ix);
}
else if (str[ix] == ')')
{
if (s1.empty() || (!s2.empty() && s1.top() < s2.top()))
{
result = 1;
break;
}
s1.pop();
}
else if (str[ix] == ']')
{
if (s2.empty() || (!s1.empty() && s2.top() < s1.top()))
{
result = 1;
break;
}
s2.pop();
}
else
{
// do nothing
}
}
if (!s1.empty() || !s2.empty())
{
result = 1;
}
cout << result << endl;
}
As methoned before, this question can be solved by just on stack, so I modified my code, and here is the single stack version. [THE KEY POINT IS NOT TO ARGUE WHITCH IS BETTER, BUT WHAT'S WRONG WITH MY CODE.]
#include <iostream>
#include <stack>
using namespace std;
int main()
{
string str;
cin >> str;
stack<char> s;
const char *p = str.c_str();
int result = 0;
while (*p != '\0')
{
if (*p == '(' || *p == '[')
{
s.push(*p);
}
else if (*p == ')')
{
if (s.empty() || s.top() != '(')
{
result = 1;
break;
}
s.pop();
}
else if (*p == ']')
{
if (s.empty() || s.top() != '[')
{
result = 1;
break;
}
s.pop();
}
else
{
// do nothing
}
p++;
}
if (!s.empty())
{
result = 1;
}
cout << result << endl;
}
When using formatted input to read a std::string only the first word is read: after skipping leading whitespate a string is read until the first whitespace is encountered. As a result, the input ( ) should match but std::cin >> str would only read (. Thus, the input should probably look like this:
if (std::getline(std::cin, str)) {
// algorithm for matching parenthesis and brackets goes here
}
Using std::getline() still makes an assumption about how the input is presented, namely that it is on one line. If the algorithm should process the entire input from std::cin I would use
str.assign(std::istreambuf_iterator<char>(std::cin),
std::istreambuf_iterator<char>());
Although I think the algorithm is unnecessary complex (on stack storing the kind of parenthesis would suffice), I also think that it should work, i.e., the only problem I spotted is the way the input is obtained.