This code really confuses me, it is using some Stanford libraries for the Vector (array) class. Can anyone tell me what is the purpose of int index = line [j] - 'a'; why - 'a'?
void countLetters(string filename)
{
Vector<int> result;
ifstream in2;
in2.open(filename.c_str());
if (in.fail()) Error("Couldn't read '" + filename + "'");
for (int i = 0; i < ALPHABETH_SIZE; i++)
{
result.add(0); // Must initialize contents of array
}
string line;
while (true)
{
getLine(in, line);
// Check that we got a line
if (in.fail()) break;
line = ConvertToLowerCase(line);
for (int j = 0; j < line.length(); j++)
{
int index = line [j] - 'a';
if (index >= 0 && index < ALPHABETH_SIZE)
{
int prevTotal = result[index];
result[index] = prevTotal +1;
}
}
}
}
The purpose of the code:
Takes a filename and prints the number of times each letter of the alphabet appears in that file. Because there are 26 numbers to be printed, CountLetters needs to create a Vector. For example, if the file is:
Characters in a string are encoded using a character set... typically ASCII on hardware common in English language systems. You can see the ASCII table at http://en.wikipedia.org/wiki/ASCII
In ASCII (and most other character sets), the numbers representing letters are contiguous. So, this is the natural way to test whether the character at index j in character-array line is a letter:
line[j] >= 'a' && line[j] <= 'z'
Your program is equivalent to that, in an algebra-kind of sense it subtracts a from both sides (knowing that a is the first character in the character set):
line[j] >= 'a' - `a` && line[j] <= 'z' - `a`
line[j] >= 0 && line[j] <= 'z' - `a`
Replacing "<= z - a" with am equivalent:
line[j] >= 0 && line[j] < ALPHABET_SIZE
where ALPHABET_SIZE is 26. This trades a dependency on knowing z is the last character of your character set for knowing how many characters are in your character set - both are a little fragile, but fine if you know you're dealing with a well-known, stable character set encoding.
A better way to check for a letter is to use the isalpha() predicate: http://www.cplusplus.com/reference/clibrary/cctype/isalpha/
"a" is at the beginning of ASII chars.
int index = line [j] - 'a';
if (index >= 0 && index < ALPHABETH_SIZE)
These two line of code is to just if line[j] is a character.
Related
I need to convert all uppercase letters to lowercase and vice-versa. If one of the elements of the string is not a valid letter of the alphabet, it must be replaced with “bug here!”. Using user-defined function
Input: evEry1
Output: EVeRY*bug here!*
I am already able to convert all uppercase letters to lowercase and vice-versa. I was also able to change nonalphanumeric elements to a single character but cannot replace it with the entire string "bug here!". I end up having error saying it cannot be converted
string flip (string w, int t){
string ch = "*bug here!*";
for (int j=0; j<w.length(); j++){
if (w[j] >= 'A' && w[j] <= 'Z')
w[j] = w[j] + 32;
else if (w[j] >= 'a' && w[j] <= 'z')
w[j] = w[j] - 32;
else
w[j] = ch;
}
return w;
}
A character is not a string and a string is not a character. So you can not replace characters with strings by using w[j] = ch;. Instead you should use the string replace method. Something like this
string flip (string w, int t){
string ch = "*bug here!*";
for (int j=0; j<w.length(); j++){
if (w[j] >= 'A' && w[j] <= 'Z'){
w[j] = w[j] + 32;
}
else if (w[j] >= 'a' && w[j] <= 'z') {
w[j] = w[j] - 32;
}
else {
w.replace(j, 1, ch); // replace the character
j += ch.length() - 1; // advance j so we don't process the replacement string
}
}
return w;
}
Note that after inserting the replacement string we have to increment j otherwise we'll start processing the replacement string.
This is untested code.
BTW given the confusion over strings vs characters, you really should change the name of the variable ch. How about str instead?
BTW I'm not seeing what the purpose of t is in the function above. It's not being used so it could be removed.
When you index the string you are looking at a single character, so
w[j] = w[j] - 32;
is ok.
When you want to insert a substring, you need to use std::string's insert function:
w.insert(j, ch);
This will allocate the extra space needed since you have a string not a single character. You then need to skip j ahead by ch.length() to move to the next original character.
First of all I am taking the string from geline(cin, s) and the input is in the form of: 100 49. And I can not take it with normal cin because I need to know where geline(cin, s) makes s empty so that means is a blank line and I should stop the program.
When passing from string '99' (or any other number below 100) to int 99 there is no problem. But when I try a number greater than 99 it gave the (number - 1). Also I found that this happens with numbers below 1000 but from 1000 to 10000 it is ok, but I tested number greater than 10^4 and it gave the (number - 1) another time.
Here is my code to convert the string
//Search how many nums are in the string wer are passing until an space or new line
int nums = 0;
for(int j = i; j < s.size(); j++){
if(s[j] == ' ' || s[j] == '\n') break;
nums++;
}
//pass to the variable time the string character by character
int time = 0;
while(nums--){
time += (s[i] - '0') * (pow(10, nums));
i++;
}
I would like to know if there is an error from my computer or I am missing something.
First of all I am taking the string from geline(cin, s) and the input is in the form of: 100 49.
Then simplest solution is to use std::istringstream:
int i1 = 0, i2 = 0;
std::istringstream( s ) >> i1 >> i2;
I am trying to solve this problem.
I am implementing it with strings. Here is my code snippet
string s,ss;
// s and ss both contains integer input.
while(s <= ss )
//while( s<=ss && s.size() <= ss.size())
{
int i = inc, j = dec; // inc and dec are middle values. both equal if odd else different
while((s[j]-'0')==9 && i < len && j>=0){
// for cases like 999
s[i] = s[j] = '0';
i++;
j--;
}
if(j<0){
s = "1" + s;
int l = s[len-1] - '0';
l++;
//cout<<l<<"\n";
s[len] = (l + '0');
}
else{
int l = s[j] - '0';
l++;
s[i] = s[j] = (l+'0');
}
if(s <= ss)
cout<<"out in wild "<<s<<" and "<<ss<<"\n";
}
cout<<s<<endl;
The problem that I am facing is when input is like 999 or 9999. The outer while loop keeps on looping even when the value of s increases, but if I add while( s<=ss && s.size() <= ss.size()) it works completely fine. Why is while(s<=ss) is not working? I rarely use the string class, so I don't understand it completely. Why don't string s= 101 and ss=99 stop the while loop?
Complete code link is here
You are comparing strings with lexicographical order, not numbers , so "101" is less than "99" (because '1' < '9') , e.g.
int main(){
std::string s = "99";
std::string ss = "101";
std::cout << std::boolalpha << (s <= ss);
}
Outputs false.
Notes:
A better design for your program would be to manipulate numbers (int or double ...) and not strings in the first place, so this kind of expressions would naturally work as you expect.
E.g. "101" + "99" is "10199", not "200" ...
But if you really need strings, consider this post to sort strings containing numbers.
As pointed by #Deduplicator, a program that needlessly overuses strings is sometimes called Stringly Typed
Also see std::lexicographical_compare
Since your input explicitly only involves positive integers without leading 0, writing a comparison function is trivial, something like : (untested)
/* Returns 1 if the integer represented by s1 > the integer represented by s2
* Returns -1 if the integer represented by s1 < the integer represented by s2
* Return 0 is both are equals
*
* s1 and s2 must be strings representing positive integers without trailing 0
*/
int compare(const std::string& s1, const std::string& s2)
{
if(s1.size() > s2.size())
return 1;
if(s2.size() > s1.size())
return -1;
for(std::size_t i = 0 ; i < s1.size() ; ++i)
{
if(s1[i] - '0' < s2[i] - '0')
return 1;
if(s2[i] - '0' < s1[i] - '0')
return -1;
}
return 0;
}
While s and ss are string variables, they are compared character by character.
In the case that you mentioned being: s = "101" & ss = "99", by first hand it will check the first character in each string, and as '1' < '9' it exit up with s < ss. I would advise you to convert those values to integers before comparison.
As the s is compared with ss in lexicographical order, I would suggest you to compare one char from tail with one char from head (one by one till you reach the middle) to solve that problem.
Below is an example code that is not working the way I want.
#include <iostream>
using namespace std;
int main()
{
char testArray[] = "1 test";
int numReplace = 2;
testArray[0] = (int)numReplace;
cout<< testArray<<endl; //output is "? test" I wanted it 2, not a '?' there
//I was trying different things and hoping (int) helped
testArray[0] = '2';
cout<<testArray<<endl;//"2 test" which is what I want, but it was hardcoded in
//Is there a way to do it based on a variable?
return 0;
}
In a string with characters and integers, how do you go about replacing numbers? And when implementing this, is it different between doing it in C and C++?
If numReplace will be in range [0,9] you can do :-
testArray[0] = numReplace + '0';
If numReplace is outside [0,9] you need to
a) convert numReplace into string equivalent
b) code a function to replace a part of string by another evaluated in (a)
Ref: Best way to replace a part of string by another in c and other relevant post on SO
Also, since this is C++ code, you might consider using std::string, here replacement, number to string conversion, etc are much simpler.
You should look over the ASCII table over here: http://www.asciitable.com/
It's very comfortable - always look on the Decimal column for the ASCII value you're using.
In the line: TestArray[0] = (int)numreplace; You've actually put in the first spot the character with the decimal ASCII value of 2. numReplace + '0' could do the trick :)
About the C/C++ question, it is the same in both and about the characters and integers...
You should look for your number start and ending.
You should make a loop that'll look like this:
int temp = 0, numberLen, i, j, isOk = 1, isOk2 = 1, from, to, num;
char str[] = "asd 12983 asd";//will be added 1 to.
char *nstr;
for(i = 0 ; i < strlen(str) && isOk ; i++)
{
if(str[i] >= '0' && str[i] <= '9')
{
from = i;
for(j = i ; j < strlen(str) && isOk2)
{
if(str[j] < '0' || str[j] > '9')//not a number;
{
to=j-1;
isOk2 = 0;
}
}
isOk = 0; //for the loop to stop.
}
}
numberLen = to-from+1;
nstr = malloc(sizeof(char)*numberLen);//creating a string with the length of the number.
for(i = from ; i <= to ; i++)
{
nstr[i-from] = str[i];
}
/*nstr now contains the number*/
num = atoi(numstr);
num++; //adding - we wanted to have the number+1 in string.
itoa(num, nstr, 10);//putting num into nstr
for(i = from ; i <= to ; i++)
{
str[i] = nstr[i-from];
}
/*Now the string will contain "asd 12984 asd"*/
By the way, the most efficient way would probably be just looking for the last digit and add 1 to it's value (ASCII again) as the numbers in ASCII are following each other - '0'=48, '1'=49 and so on. But I just showed you how to treat them as numbers and work with them as integers and so. Hope it helped :)
I am currently doing a caesar cipher program. It should encrypt for both lower and upper case.
e.g
If I typed in a, it will then shift the keys by 3 and the final output will become d.
Take a look at my codes
char c;
c = (((97-52)+3) % 26) + 52;
cout << c;
The letter 'a' has an ASCII code of 97.
So by right
1) ((97-52)+3) will give you 48
2) 48 % 26 will give you 8 since 48/26 will give you a remainder of 8.
3) 8 + 52 = 60(which will by right give you a value of '>' according to the ascii table)
but my output that I have got is J and I don't understand which am I getting the output of 'J' instead of '>'
My concepts might be wrong so I need help.
Let me link ASCII chart I use first: http://pl.wikipedia.org/wiki/ASCII
The website is polish, but table itself is in english.
I think it's plainly obvious that problem is the equatation you use:
(((letter-52)+3) % 26) + 52;
Actually first letter in ASCII is 65(hexadecimal 0x41 - follow with the chart provided).
Your idea with the modulo would be fine, if there were no chars between letter blocks in ASCII. But there are (again check up chart).
That is why you should manually check if the sign:
is a capital letter: if (letter >= 0x41 && letter <= 0x5a)
is a non-capital: if (letter >= 0x61 && letter <= 0x7a)
Usually when making Ceasar cipher, you should follow these:
Replace a capital letter with capital letter moved in the alphabet by a given number.
If the letter would be out of alphabet scope, continue iteration from the start of alphabet (X moved 5 to the right would give C).
Other chars stay the same
Now let's implement this (in code I'll use letter values of chars - to avoid mistakes):
#include <iostream>
#include <cstdlib>
using namespace std;
string Ceasar(string input, int offset)
{
string result = "";
for (int i = 0; i < input.length(); ++i)
{
// For capital letters
if (input[i] >= 'A' && input[i] <= 'Z')
{
result += (char) (input[i] - 'A' + offset) % ('Z' - 'A') + 'A';
continue;
}
// For non-capital
if (input[i] >= 'a' && input[i] <= 'z')
{
result += (char) (input[i] - 'a' + offset) % ('z' - 'a') + 'a';
continue;
}
// For others
result += input[i];
}
return result;
}
int main()
{
cout << Ceasar(string("This is EXamPLE teXt!?"), 8).c_str();
system("PAUSE");
}