Replace specific characters in line, c++ - c++

I am working on a program to decrypt text with a certain key. I'm trying to use replace() but it doesn't seem to be working. For example, qwert should decrypt to hello, but the output is hlllo; in this case the w in qwert gets decrypted to e but then re-decrypted to l.
input:
xnm ceuob lrtzv ita hegfd tsmr xnm ypwq ktj
should come out as:
the quick brown fox jumps over the lazy dog
I'm getting:
oga yaacd brozn aox gamav ovar oga lazy dog
How can I fix this?
int main()
{
// ...
myFile.open("decrypt.txt");
while (myFile.good())
{
getline(myFile, line2);
// now line2 is, e.g., "xnm ceuob lrtzv ita hegfd tsmr xnm ypwq ktj"
// help here
for (int i = 0; i < 26; i++)
{
replace(line2.begin(), line2.end(), key[i], fox[i]);
}
v.push_back(line2);
}
myFile.close();
for (int i = 0; i < numline; i++)
{
cout << "line " << i <<" = " << v[i] << endl;
}
return 0;
}

By making 26 separate substitutions, the later ones are stepping on the results of the earlier ones. You need to find a way to make each substitution occur only once per character.

You need to decrypt each character once. Instead of having two arrays, key and fox, which (apparently) contain characters to substitute, you might consider building a map between input characters and their decrypted versions. Then you can simply walk over the input string, decrypting a character at a time.
std::map<char, char> lookup;
// populate lookup such that lookup['q'] = 'h', lookup['w'] = 'e', etc.
// walk over line2, decrypting a character at a time.
for (int i = 0; i < line2.length(); i++)
{
char c = line2[i];
char d = lookup[c];
line2[i] = d;
// or, if you want to keep it on one line:
// line2[i] = lookup[line2[i]];
}

In C++ you can access and modify string elements with square brackets. For example:
String str("dog");
str[1] = 'c';
//str = "dcg"
So you can use this notation instead of replace(). If replacing doesn't work as you intend it to then maybe your key is wrong.

Related

Logical error from std string find method and count algorithm

When I was about to solve a project euler problem in C++, this was some of the experimentation code I made. It produced a quite unexpected result, so I solved it in an other programming language. But I really want to understand why this error occured. The part one of the code executes as expected, it does not print AAAA. But in part two, the logically equivalent code (the if statement) executes when the variable s is AAAA. And I have no idea why. I hope I made my problem clear, every answer given is highly appreciated! Thanks :)
Note: i'm using count from <algorithm>
#include <iostream>
#include <algorithm>
using namespace std;
int main (int argc, char** argv) {
string alt = "LOA";
// CODE PART 1
string stringToFind = "AAA";
string df = "AAAA";
if (df.find(stringToFind) == string::npos && count(df.begin(), df.end(), 'L') <= 1) {
cout << df; // this does not print AAAA
}
/* CODE PART 2:
this was an attempt to print out every four length string combination
of the characters L, O, A where strings with three A's in a row and
more than one L were excluded.
*/
for (size_t i = 0; i < 3; i++) {
char c1 = alt[i];
for (size_t iT = 0; iT < 3; iT++) {
char c2 = alt[iT];
for (size_t itr = 0; itr < 3; itr++) {
char c3 = alt[itr];
for (size_t itrI = 0; itrI < 3; itrI++) {
char c4 = alt[itrI];
string s = string(&c1)+string(&c2)+string(&c3)+string(&c4);
if (s.find(stringToFind) == string::npos && count(s.begin(), s.end(), 'L') <= 1) {
cout << s << endl; // this however, does print out AAAA
}
}
}
}
}
return 0;
}
You have written
string s = string(&c1)+string(&c2)+string(&c3)+string(&c4);
You meant:
string s = string(1,c1)+string(1,c2)+string(1,c3)+string(1,c4);
or
string s = string(&c1,1)+string(&c2,1)+string(&c3,1)+string(&c4,1);
In your code, you have invoked the string constructor which takes a pointer to a nul-terminated array of char, but you given it a pointer to a single char. That's going to invoke all sorts of undefined behaviour.
Either invoke the constructor that takes a a counter + a single char or, the one which takes a pointer and a count, and you can tell it there is exactly one character at that address.
Edit There is no constructor which takes a single char. You have to give it a count + char. Which means it's not so pretty.

Copy words from c-string into 2D array of c-strings

So I need to turn a c-string of characters (letters and spaces) into a 2-dimensional array of c-strings. Each "row" of the 2D array must consist of letters and only letters. Essentially I need to take the words of a sentence and make an array out of them.
For example: "im upset that on nov th my brandnew bmw lis were stolen" should be turned into 2d c-string array like: "im","upset","that","on","nov","th","my","brandnew","bmw","lis","were","stolen".
(Notice that there are two space characters between "th" and "my" & "my" and "brandnew")
The following code gives me some interesting output in my console...
char document[201] = "im upset that on nov th my brandnew bmw lis were stolen";
char documentArray[13][201];
for (int i, k, j = 0;document[k] != '\0';)
{
if (isspace(document[k]))
{
cout << "found a space" << endl;
k++;
while (isspace(document[k]))
{
k++;
}
i++;
j = 0;
}
if (isalpha(document[k]))
{
documentArray[i][j] = document[k];
k++;
j++;
}
}
for (int i = 0; i < maxWords +1; i++)
{
cout << documentArray[i] << endl;
}
The output produced has some weird stuff in it. I don't know what it means (if you could tell me that would be awesome). Could you please help me solve this issue?
Here's the console output:
im\203\377
upset
that
on
nov
th
my\3261
brandnew
bmw_\377
lis
were
stolen\301$r\377
\377
after the line with the j++; insert the following
if (j < 201) {
documentArray[i][j+1] = '\0'; # terminate the c string
} else {
documentArray[i][j] = '\0'; # cannot terminate the c string, overwrite the last char to terminate the string
}
But please make sure that every read AND write operation NEVER exceeds the array dimensions.
Your array limits are documentArray[0..12][0..200].
Please ALWAYS check that. => http://en.wikipedia.org/wiki/Buffer_overflow
Try adding a terminating null character to the end of your C strings when copying into the 2D array.
In C string are represented by arrays of characters terminated by a '\0' character. The strange codes you are seeing are likely the result of the '\0' not being encountered and the print running of the end of the character array.

C++ Add random characters into a string array

So I want to create 1000 words with a length of 5 random characters. In my main I have word[1000] but when I try to run this code, it gives me an error saying "Expression:string subscript out of range". I'm not sure why it does that because I thought string arrays were 2 dimensional? If anyone could tell me why my code is wrong I'd appreciate it. Thanks.
void createText(string w[], int seed) {
char ch;
srand(seed);
for(int i = 0; i < 1000; i++) {
for(int j = 0; j < 5; j++) {
ch = ('A' + rand() % 26);
w[i][j] = ch;
}
}
for(int i = 0; i < 1000; i++) {
cout << w[i];
}
cout << endl;
}
I suppose that the array w does not have 1000 elements, also remember that here you will get a copy of string w[]. Better would be passing a pointer to w (string* w), then You will have very clearly what is wrong. remember also that cout writes the string out untill it reaches a '\0' character, this also might be the cause. Quick session with gdb will help:
gdb program
...
run
bt full
should pinpoint Your problem. if it's some kind of IDE, learn how to debug in it. Valgrind or some other memcheck like visual leak detector or luke stackwalker will also show you some tips about bad initialization or unmentioned memory leaks.
If an array is bidimensional, you can't print its values like w[i]. You must print always keeping in mind that the array is bidimensional, which means that the output must be done like cout << w[i][j];
In addition, you're passing an array of strings as an argument, and what you're doing is add characters to every single position, which means that you won't actually have nothing but 1000 characters inserted into that string (because you actually added "one-char" strings), so you'll only put 200 words with a length of 5 characters each one. Insert strings directly, and you'll get your 1000 words, but first find a way to build strings with random characters.
Something like:
for(conditions){
for(conditions){
build a word
}
array[x][y] = string
}
I guess it is similar to what you intended to do

Read from string (possible array usage?) C++

I'm attempting to write alil function here which basically reads from a string. It reads every three characters and evaluates it using the pre-condition (if statement). If conditions are met, it would replace those three letters with new three letters. Then it would output the new string.
I tried writing the code but cant seem to get the logic right. the program runs but it doesn't print out anything. Dont mind the function name and the inaccuracy. I'm just doing a sample function to test this out.
string amino_acids(string line)
{
string acid;
string acids;
string newline;
for( int i= 0; i < line.length(); i++)
{
acid = line[i];
}
for (int i = 0; i < 3; i++)
{
acids = acid[i];
if(acids == "GUU")
{
acids = "ZAP";
}
newline = acids;
}
cout << "Acids: " <<newline <<endl;
return newline;
}
for( int i= 0; i < line.length(); i++)
acid = line[i];
Say line contains "abcd", this loop is going to do:
acid = 'a';
acid = 'b';
acid = 'c';
acid = 'd';
Only the last assignment has any lasting affect. If you need to actually get three characters from line into acid - you probably want to use += to add characters into acid, rather than =. But, if you loop over all of line like this, you'll end up doing acid = line;. I assume you want something more like acid = line.substr(0, 3)?
for (int i = 0; i < 3; i++)
{
acids = acid[i];
This is going to crash. acid is definitely a single character string, and you're indexing into acid[1] and acid[2] on the 2nd and 3rd iterations. While you're learning C++, you should probably use .at(i) which will throw an exception when you attempt to use an invalid index - you can catch the exception and at least have some indication of the problem. As is, it's undefined behaviour.
To use at, you need a try / catch block... the basic form is:
int main()
try
{
...your code in here...
some_string.at(i);
}
catch (const std::exception& e)
{
std::cerr << "caught exception: " << e.what() << '\n';
}
More generally, try putting some std::cout statements throughout your code so you know what values your variables actually have... you would easily have seen that they weren't what you expected. Alternatively, use an interactive debugger and watch the affect of each statement's execution.
Indexing a std::string with the [] operator yields a char, for which there just happens to be an overloaded operator= for strings.
Even if you were looping as I believe you intended (which, as the comments on the question mention, you probably aren't) because acids (which takes the value of a single character) will never be equal to the three character string you're comparing it to. Thus, no replacements will be performed.
To do what you want, try something like this:
for (int i = 0; i + 3 < line.length(); i += 3) // counting by 3 until end of line
{
if (line.substr(i, 3) == "GUU") // if the substring matches
{
line.assign("ZAP", i, 3); // overwrite it with new substring
}
}
return line;
Reading from your description, you want something like so
//note below does not compile, its just psuedo-code
string amino_acid(const string& sequence){
string result = sequence; //make copy of original sequence
For i = 0 to sequence.length - 3
string next3Seq = sequence(i,3); //grab next 3 character from current index
If next3Seq == 'GUU' //if the next next three sequence is 'GUU'
then result.replace(i,3,'ZAP'); //replace 'GUU' with 'ZAP'
EndIf
EndFor
return result;
}
You can use that as a start to code. Good Luck.
According to my understanding of your question. I have written some code. Please look below
string acids;
string newLine;
int limit=1;
for(int i=0;i<line.length();i++)
{
acids=acids+line[i];
if(limit==3)//Every 3 characters
{
if(acids == "GUU")
{
acids = "ZAP";
}
limit=1;
acids=""
newline=newline+acids;
}
limit++;
return newline;
}

C++ how make a 2D array using strings and spaces instead of ints

I am making a Sudoku program and my i have a test.txt file that reads
53__7____
6__195___
_98____6_
8___6___3
4__8_3__1
7___2___6
_6____28_
___419__5
____8__79
where the "_" are actually spaces. The reason i give you _ is so you can see that there are literally only 9 characters on each line.
I was thinking that I would have to do something like having GRID[row][column], however I frankly don't know what types I should put my arrays as and I am just lost.
I simply want to make it so when i want to output say GRID[0][0] it returns 5, while if i ask for GRID[0][3] it returns a ' '.
It is getting it so the array store both the numbers and the spaces is where i am getting completely lost
What I currently have tried so far:
int main()
{
ifstream myfile(test.txt);
string line;
char sudoku_grid[9][9];
if (myfile.is_open())
{
while(myfile.good())
{
getline(myfile, line);
cout << sudoku_grid[line] << endl;
}
myfile.close();
}
else cout << "error";
return 0;
}
it returns the error line 12: no match for 'operator [ ]' in 'sudoku_grid[line]'
Here is my attempt though guidelines through you guys:
int main()
{
ifstream myfile(test.txt);
string line;
char sudoku_grid[9][9];
if (myfile.good())
{
for(int i = 0; i < 9; i++)
{
getline(myfile, line);
for(int j = 0; j < 9; j++)
{
if (line[j] == ' ')
sudoku_grid[j][i] = -1;
else sudoku_grid[j][i] = line[i];
}
cout << sudoku_grid[i] << endl;
}
myfile.close();
}
else cout << "error";
return 0;
}
The result is a very awkward answer of strange letters and a new numbers.
I'll just give you the algorithm/logic, not going to write the code for you. Try it and come back when stuck.
Initialize output in memory 2D array: numbers[9][9]
Open the file
Until there is no line left in the file:
a. Get the line i
b. Until there are no more characters in the line:
b1. Get each character of the line c
b2. If the character is not space, then numbers[i]=c, else numbers[i]=-1
Your array can be made up of int and in b2 if a whitespace is encountered you can insert -1 to indicate the absence of a number. Of course your code manipulating numbers array needs to take that into account.
Since you need to store both chars and integer type values, use char. each of your integer lies in the range 0-9, so can be stored as a character.
char Grid[9][9];
now you can read each character from the string and store it in the array. It will not only keep your spaces intact but also each character. Always remember to use ASCII codes to access the elements of the grid. For 0-9, ASCII codes are 48-57, ASCII code for space is 32.
Hope it helps...
Edit code: Here is the simplest example... PLace your test file in d:, or edit the path of file in code
int main (void)
{
FILE *fp = fopen("d:\\test.txt","r");
char sudoku_grid[9][9], ch;
// I am assuming that file is valid and data in that is also valid
if(fp)
{
for(int i = 0; i < 9; i++)
{
for(int j = 0; j < 9; j++)
{
//too read each character
ch = fgetc(fp);
sudoku_grid[i][j] = ch;
}
// to read '\n' from the line
ch = fgetc(fp);
}
//for checking if data went correctly
for(int i = 0; i< 9;i++)
{
for(int j= 0; j<9;j++)
cout<<sudoku_grid[i][j];
cout<<endl;
}
}
return 0;
}
In the first code you get the error message because sudoku_grid can
only be indexed by numbers and not by strings.
In the second code the line
sudoku_grid[j][i] = line[i];
should probably be
sudoku_grid[j][i] = line[j];
Does this answer your question?