Given a global vector list of ASCII codes and corresponding number values and a string, like 000.00-000.0.0.0, this function takes an input token strings 2-char or 3-char long and replaces it with a single ASCII symbol that represents the number value between 0 and 184, then returns the shortened string without deliminator as out. Also, in reverse (direction 1) given the ASCII symbol it converts back to the number string and returns.
//looks for input string in vector and returns output, 'c' is check row, 'r' is return row
string vectorSearch(string &check, int n, int c, int r)
{
if (check.length() <= 1)
return check;
if (list[n][c] == check || list[n][c] == ('0'+check)) //adds leading zero if 2char long
return list[n][r];
else
return vectorSearch (check, ++n, c, r);
}
//this function takes an ontology and either changes from single char
//to string or takes strings and converts to char representation
string Lexicon::convertOntology(string input, int direction, string out, string temp)
{
if (input == "" && temp == "")
return out; //check for completed conversion
else {
if (input[0] == '.' || input[0] == '-' || input == "") { //found deliniator or endk
if (input != "") return convertOntology(input.substr(1),direction,
out+=vectorSearch(temp, 0, direction, 1-direction), "");
else return convertOntology("", direction,
out+=vectorSearch(temp, 0, direction, 1-direction), "");
} else
return convertOntology(input.substr(1), direction, out, temp+=input[0]); //increment and check
}
}
These functions work fine except for on output after the last char is parsed. With a break on the line return convertOntology(input.substr(1), direction, out+=add, temp); there is an error when input == "" and temp == "0" - the last pass through vectorSearch() should clear the temp and add the temp char to the out string, since the temp is == 1char then it should be returned from vectorSearch() as it is. Then clear the convertOntology() return check of input and temp == "". But, it never reaches a break on the first line of vectorSearch() and there is an
Unhandled exception at 0x77bc15de exception: std::out_of_range at memory location 0x0035cf1c
What is going on? Is this an issue with recursion backtracking through returns and I am missing a return somewhere to break the recursion loop?
for the case where temp == "" and input != "" you call input.substr(1) which is, well, out of range.
Even if you don't get to the else part,
input.substr(1)
will throw an exception when the input string is exactly one character long.
Seems it doesn't - input.substr(input.size()) is allowed, and returns an empty string.
You will later likely have a similar problem in VectorSearch. If there is no match, you will increment n until it gets out of range.
Related
Say I take in a string of input and I wanted to check if the user entered a negative number.
bool isNegative(string input[]) {
int i = 0;
if (input[i] == "-") {
return true;
} else {
return false;
}
}
I tried a boolean function to check if the first character is a - sign, representing negative numbers e.g -5, -25.
However, my Netbeans gave me this error:
main.cpp:39:25: error: ISO C++ forbids comparison between pointer and integer [-fpermissive]
anyone knows what this means?
There are two problems with your code:
You declare i that never changes. This is the same as doing input[0]
You compare a character to a string. Instead of "0" (double quotes) you need '0' (single quotes).
Fixing these two problems will fix your code.
Note: You can write this function in a single line:
bool isNegative(string input) {
return input[0] == '-';
}
You need to use single quotes, which represent a single character, rather than using double quotes, which represent a string.
if (input[i] == '-')
When I run this, the if statement is supposed to compare only the first element of both arrays. It works fine as long as array "ans" only contains y or Y, but if I enter a "yes", etc, it comes back false and shoots down to else.
char y[2]= "y";
char n[2] = "n";
char ans[5];
printf("Answer yes of no. (y/n) ");
scanf(" %s", ans);
if (strcasecmp(&ans[0], &y[0]) == 0)
{
printf("You said yes.\n");
printf("%c, %s\n", y[0], ans);
}
else if (strcasecmp(&ans[0], &n[0]) == 0)
{
printf("You said no.\n");
}
else
{
printf("hmm?\n");
}
Not really, strcasecmp() compares two strings, not two characters, even if you pass it the pointer to their first characters, it still compare two strings that start from this character until a terminating '\0'.
You can compare their first characters ignoring case like this:
if (toupper(ans[0]) == toupper(y[0])))
Use strncasecmp instead of strcasecmp, so that you can compare just the first character rather than the entire string. Change:
if (strcasecmp(&ans[0], &y[0]) == 0)
to:
if (strncasecmp(ans, y, 1) == 0)
and similarly for the rest.
I'm working on an automatic summarization system in my C++ class and have a question regarding one of the ASCII comparisons I'm doing. Here's the code:
char ch;
string sentence;
pair<char, char> sentenceCheck;
int counter = 0;
while (!ifs2.eof())
{
ch = ifs2.get();
ch = tolower(ch);
if (ch == 13)
ch = ifs2.get();
if (ch != 10 && ch != '?' && ch != '!' && ch != '.')
sentence += ch;
sentenceCheck.first = sentenceCheck.second;
sentenceCheck.second = ch;
cout << sentenceCheck.first << "-" << (int)sentenceCheck.first << " ---- " << sentenceCheck.second << "-" << (int)sentenceCheck.second << endl;
if(sentenceCheck.second == ' ' || sentenceCheck.second == 10 || sentenceCheck.second == -1)
{
if(sentenceCheck.first == '?' || sentenceCheck.first == '!' || sentenceCheck.first == '.')
{
istringstream s(sentence);
while(s >> wordInSentence)
{
sentenceWordMap.insert(pair<string, int>(wordInSentence, 0));
}
//sentenceList.push_back(pair<string, int>(sentence, 0));
sentence.clear();
}
}
}
What is being done here (with the two if statements) is checking whether a new sentence has begun in the text that is to be analyzed and dealt with later. The conditionals work but only because we discovered that we have to check for that -1 as well. Any ideas what that represents?
-1 doesn't represent anything in ASCII. All ASCII codes are in the range [0, 127]. It's not even guaranteed by C++ that -1 is a valid value for a char.
The problem is that you're not checking the return value from ifs2.get(), which returns an int (not a char!) that may be -1 on end of file. The proper way to check for this is
int ch = ifs2.get();
if (!ifs2)
// break the loop
because the EOF value is not guaranteed to be -1 (it's actually std::char_traits<char>::eof()).
(Btw., you shouldn't write ASCII codes as magic numbers; use \n for linefeed, \r for carriage return.)
The while is incorrectly structured: you need to check eof() immediately after get():
for (;;)
{
ch = ifs2.get();
if (ifs2.eof()) break;
ch = tolower(ch);
if (ch == 13)
{
ch = ifs2.get();
if (ifs2.eof()) break;
}
...
}
The -1 is probably the EOF indicator.
Note (as has already been stated) get() returns an int, not a char.
As an ASCII character -1 doesn't represent anything (which is to say -1 is not a valid ASCII value). As the return value from get() it means that the read operation failed - most likely due to the end of file being reached.
Note that the eof() function doesn't return true if the next call to get will fail because of the end of file being reached - it returns true if the previous call to get failed because of the end of file being reached.
It's not ASCII, it's an error returned by istream::get
ch = ifs2.get();
It's probably EOF, i.e. you've run out of input.
The fact that checking for -1 works is an accident, and has nothing to
do with ASCII values (which only use 0 to 127). Your code will fail
if either plain char is unsigned (compile with /J with VC++, I think),
or EOF isn't -1 (rare, but all that's guaranteed is that it is
negative). You're code will also fail if the input happens to be
Latin-1, and it contains a 'ÿ'.
The basic problem in your code is that you're not checking for end of
file correctly. Putting the test at the top of the loop doesn't work;
you need to test for failure (not eof()) after input, before using
the value read. There are several ways of doing this; in your case, the
simplest is probably to use:
if ( !ifs2.get(ch) ) {
// Input failed...
}
Alternatively, you can make ch an int, and do:
ch = ifs2.get();
if ( ch == EOF ) {
// Input failed...
}
This has the advantage that the following call to tolower is no longer
undefined behavior (tolower takes an int, which must be in the range
[0...UCHAR_MAX] or EOF—if plain char is signed, you aren't
guaranteeing this). On the other hand, it doesn't allow chaining, i.e.
you can't write the equivalent of:
while ( ifs2.get( sentenceCheck.first )
&& ifs2.get( sentenceCheck.second ) ) {
// ...
}
(which could be useful in some cases).
FWIW: the technique you're using is something called a sliding window
into a stream, and it's worth pushing it off into a separate class to
handle the logic of keeping the window filled and up to date.
Alternatively, a simple state machine could be used for your problem.
And I'd definitely avoid using magic constants: if you want to check for
a carriage return, compare with '\r'. Similarly, newline is '\n',
and in the outer if, it looks like you want to check for whitespace
(isspace( static_cast<unsigned char>( sentenceCheck.second ) )),
rather than comparing for the values.
I might also add that your code fails to correctly handle sentences that
end with a quote, like This is the "text in your input."; it also
fails for abbreviations like Mr. Jones is here.. But those problems
may be beyond the scope of your assignment. (The abbreviations one is
probably not fully solvable: sometimes "etc." is the end of a
sentence, and sometimes it's not.)
I have calculator code where I need to save a given line (one line at a time calculator) based on a certain character like 'M' being present at the end of the string. Also if 'M' is anywhere in the string then add the last saved string in place of that 'M'.
I thought this could be easily done by (pseudo code),
foreach input element
if input element == 'M' && is last element
save = true
erase M element
if input element == 'M' && save != true
insert saved string into input
erase 'M' from input
if save == true
Set save string = input;
I attempt to do this in the method below but it is not working. I am not sure where or how to save the string so that it doesn't get reset on every line. I get "string subscript out of range" (in another class, but due to this change) when I try to use an 'M' at the end of input.
const string operators = "*/+-";
const string memorize = "M";
list<string> lex(string input)
{
list<string> tokens;
bool save = true;
string saveInfo = "2";
string token;
for (unsigned int i = 0; i < input.length(); i++)
{
// Check if we need to save string element to memory
if ((memorize.find(input[i]) != string::npos) && (i == input.length() - 1))
{
save = true;
// Remove 'M' from end of string
input.erase(i);
}
// Check if 'M' is element
if (memorize.find(input[i]) != string::npos && !save)
{
// Insert saved string
input.insert(i, saveInfo);
// Remove M from string
input.erase(i);
}
// Save input
if (save)
{
saveInfo = input;
}
if (operators.find(input[i]) != string::npos)
{
// Add any token we've created so far
if (token.length())
{
tokens.push_back(token);
token.clear();
}
// Add this operator as a separate token
token.push_back(input[i]);
tokens.push_back(token);
token.clear();
}
else
{
// Grow the current token
token.push_back(input[i]);
}
}
// Any stragglers?
if (token.length())
{
tokens.push_back(token);
}
// Clean 'em up
for (list<string>::iterator i = tokens.begin(); i != tokens.end(); ++i)
{
*i = clean(*i);
}
return tokens;
}
saveInfo is currently just being set to "2" every time until I figure out where my string variable should be to keep the saved string instance each time.
Is this the right way to go about this problem? Is there a better way? Do you know why this isn't working?
EDIT:
example input:
INPUT: 2+1M
OUTPUT: 3 **2+1 is saved
INPUT: M+5 **2+1 is inserted into this input string at 'M'
OUTPUT: 8
I have not worked with C++ in a long time, any help is appreciated!
First thing that comes to mind is this: you're iterating over a sequence while you modify it by adding and removing items. that's bound to cause tears since your indices are wrong after your insertion/deletion.
I am trying to write a bool function that looks at the first index in an array which contains a positive or negative number and classifies if it is a negative sign (i.e. -). If it is a negative Sign it returns false everything else returns true. I am trying to figure out how to compare the negative sign. The following code give an error because of the '-'
bool BigNum::get_positive() const
{
char '-';
if(digits[0] == '-')
{
return false;
}
else
{
return true;
}
}
char '-';
The compiler thinks you're trying to declare a char, but that's not a valid declaration.
Your entire function could be replaced with:
return (digits[0] != '-');
Of course, this is assuming that [0] is a valid index of digits. If not, bad things will happen. If you know the length of the array, you can do a check like this:
if( digits_length < 1 )
return false;
return (digits[0] != '-');
you must delete or comment "char '-';"
Mistake lies in line char '-'.
'-' is supposed to be stored in some variable which later could be used in if clause to compare. This is a syntactical error because you havn't defined a storage for '-'.
Otherwise as pointed above just delete this line and get away with using '-' in if (as you have already done it)