I want to increment or decrement characters, but have them cycle back to a when going beyond z and to z when going before a.
For example incrementing 'w' by 2 gives 'y' and decrementing 'w' by 2 gives 'u'.
Another example decrementing 'w' by 28 gives 'u' and decrementing 'a' by 256 gives 'e'.
I've figure out how to increment: char(int(A[i]+B-97)%26 +97) where B is the shift amount and A[i] is current character.
Don't overcomplicate. Use modulo to keep the increment or decrement amount in a range of 26 characters, then simply do a range check:
char cyclicIncrementDecrement(char ch, int amount)
{
int newValue = int(ch) + (amount % 26);
if (newValue < 'a') newValue += 26;
if (newValue > 'z') newValue -= 26;
return char(newValue);
}
This method of course assumes ch already is in range of 'a' to 'z'. If not, you need to handle that (put it in range or throw an exception or whatever is appropriate for your application).
Running this:
int main()
{
std::cout << cyclicIncrementDecrement('w', -2) << std::endl;
std::cout << cyclicIncrementDecrement('w', 2) << std::endl;
std::cout << cyclicIncrementDecrement('w', -28) << std::endl;
std::cout << cyclicIncrementDecrement('a', -256) << std::endl;
std::cout << cyclicIncrementDecrement('z', -256) << std::endl;
std::cout << cyclicIncrementDecrement('z', -51) << std::endl;
std::cout << cyclicIncrementDecrement('z', -52) << std::endl;
}
gives:
u
y
u
e
d
a
z
Using modular arithmetic, calculate your answer as modulo 26 and then add 'a' (ASCII 97) to your result.
char cyclic_increment(char ch, int n) {
int tmp = ((ch - 97) + n) % 26;
if (tmp < 0 )
tmp += 26;
return (char)(tmp + 97);
}
Alternatively, you could write the above (without an if) as:
char cyclic_increment(char ch, int n) {
return (((ch - 'a') + n) % 26 + 26) % 26 + 'a';
}
This handles both positive and negative offsets:
unsigned char az_cyclic(int in_ch)
{
constexpr int mod = 26; // There are 26 letters in the English alphabet
int offset = (in_ch - 'a') % mod; // (ASCII To zero-based offset) Mod_26 remainder
if (offset < 0) // If negative offset,
offset += mod; // normalize to positive. For example: -1 to 25
return 'a' + offset; // Normalize to ASCII
}
Use-cases:
int main()
{
unsigned char out_ch = '\0';
out_ch = az_cyclic('a' - 1); // 'z'
out_ch = az_cyclic('a' - 1 - 26); // 'z'
out_ch = az_cyclic('a' - 2); // 'y'
out_ch = az_cyclic('a' + 4); // 'e'
out_ch = az_cyclic('a' + 4 + 26); // 'e'
out_ch = az_cyclic('a' + 2); // 'c'
return 0;
}
Related
I am aware that this question has been asked a few times, and I may have missed the question that answers my specific problem however I cannot seem to find one that gives me an answer that works for me.
When I am decrypting a Caesar Cipher it doesn't seem to wrap around correctly, my code seems to follow the specific mathmatics for the caesar cipher but it seems to return junk output when it's supposed to wrap around. My code is as follows, including a system I used to test the problem.
#include "main.h"
#include <QCoreApplication>
#include <QDebug>
String caesarCipher(QString in, int shift, bool decrypt)
/*
* Caesar shift is mathmatically represented as e = (q + s) mod 26
* Decryption is represented as d = (q - s) mod 26
* ROT13 is a caesar shift with 13 shift
*/
{
QString out;
if (!decrypt)
{
for (int i = 0; i < in.length(); ++i)
{
if (in[i] >= 'a' && in[i] <= 'z')
{
int q = (in[i].unicode() - 'a');
int e = (q + shift) % 26;
out += e + 'a';
}
else if (in[i] >= 'A' && in[i] <= 'Z')
{
int q = (in[i].unicode() - 'A');
int e = (q + shift) % 26;
out += e + 'A';
}
else
out += in[i];
}
return out;
}
else
{
for (int i = 0; i < in.length(); ++i)
{
if (in[i] >= 'a' && in[i] <= 'z')
{
int q = (in[i].unicode() - 'a');
int d = (q - shift) % 26;
int r = d + 'a';
out += r;
}
else if (in[i] >= 'A' && in[i] <= 'Z')
{
int q = (in[i].unicode() - 'A');
int d = (q - shift) % 26;
int r = d + 'A';
out += r;
}
else
out += in[i];
}
return out;
}
}
int main() // Testing
{
QString testString = "abcdefghijklmnopqrstuvwxyz";
QString upperTest = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const int shifting = 3;
qDebug() << "Test String: " << testString;
qDebug() << "Test String (Upper): " << upperTest;
{
QString e = caesarCipher(testString, shifting, false);
QString E = caesarCipher(upperTest, shifting, false);
QString d = caesarCipher(e, shifting, true);
QString D = caesarCipher(E, shifting, true);
qDebug() << "Shift amount: " << shifting;
qDebug() << "Encrypt (Lower): " << e;
qDebug() << "Encrypt (Upper): " << E;
qDebug() << "Decrypt (Lower): " << d;
qDebug() << "Decrypt (Upper): " << D;
}
return 0;
}
The expected result is
Test String: "abcdefghijklmnopqrstuvwxyz"
Test String (Upper): "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Shift amount: 3
Encrypt (Lower): "defghijklmnopqrstuvwxyzabc"
Encrypt (Upper): "DEFGHIJKLMNOPQRSTUVWXYZABC"
Decrypt (Lower): "abcdefghijklmnopqrstuvwxyz"
Decrypt (Upper): "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Press <RETURN> to close this window...
The result I get:
Test String: "abcdefghijklmnopqrstuvwxyz"
Test String (Upper): "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Shift amount: 3
Encrypt (Lower): "defghijklmnopqrstuvwxyzabc"
Encrypt (Upper): "DEFGHIJKLMNOPQRSTUVWXYZABC"
Decrypt (Lower): "abcdefghijklmnopqrstuvw^_`"
Decrypt (Upper): "ABCDEFGHIJKLMNOPQRSTUVW>?#"
Press <RETURN> to close this window...
I have tried to move code around, change where the shift is removed, where the modulo is done and where the 'a' character is added
For reference the code was initially before I altered it for readability:
for (int i = 0; i < in.length(); ++i)
{
if (in[i] >= 'a' && in[i] <= 'z')
out.resultString += (((in[i].unicode() - 'a') - shift) % m) + 'a';
else if (in[i] >= 'A' && in[i] <= 'Z')
out.resultString += (((in[i].unicode() - 'A') - shift) % m) + 'A';
else
out.resultString += in[i];
}
The % operator can return negative results when used with negative numbers. In your case, when decrypting an 'a', q will be 0, d will be (-3 % 26), which can be -3.
The solution is to ensure the number is positive before calculating the remainder:
int d = (q - shift + 26) % 26;
Or, if the shift amount is unknown, or can be more than 25, check if d is negative and add 26 to it after your initial calculation.
As i know , the " formula " of Caesar Shifting is (x + k ) % 26 , where k is the shifting value and decryption just replace " + " to " - ".
but my code does not work when k > 10 (after i tested k = 10 , i find that the "shift" of the first few characters is wrong, so I estimate that k > 10 will be wrong (the number of incorrect characters increase) as well. ). I first change the characters to ASCII and then do the calculation. Finally change it back to characters.
Here are my code.
#include <iostream>
#include <string>
using namespace std;
int main() {
string target;
char s;
int k, i, num, length, j;
cin >> s >> k;
getline(cin, target);
for (j = 0; j <= (int)target.length(); j++) {
if ((target[j]) = ' ') {
target.erase(j, 1);
}
}
length = (int)target.length();
if (s == 'e') {
for (num = 0; num <= length; num++) {
if (isupper(target[num]))
target[num] = tolower(char(int(target[num] + k - 65) % 26 + 65));
else if (islower(target[num]))
target[num] = toupper(char(int(target[num] + k - 97) % 26 + 97));
}
}
else if (s == 'd') {
for (num = 0; num <= length; num++) {
if (isupper(target[num]))
target[num] = tolower(char(int(target[num] - k - 65) % 26 + 65));
else if (islower(target[num]))
target[num] = toupper(char(int(target[num] - k - 97) % 26 + 97));
}
}
cout << target;
return 0;
}
Let me put down the case which i failed to run.
input:
d 10 n 3 V 3 D 3 N _ M Y N 3 _ S C _ N 3 L E ( input d / e first, then shifting value, finally the sequence of string require to " change ", the space is required to delete. )
the expected output:
D3l3t3d_cod3_is_d3bu
my output:
D3l3:3d_cod3_i9_d3b;
Thanks!
Your issue is that when decoding you end up with negative numbers. With k == 13 the expression 'T' - k - 65 gives -7. -7 % 26 is still -7. -7+65 is 58 which isn't a letter.
You can avoid negative numbers by simply setting k to 26 - k when decoding.
Your code then simplifies to:
if (s == 'd') {
k = 26 - k;
}
for (num = 0; num <= length; num++) {
if (isupper(target[num]))
target[num] = tolower(char(int(target[num] + k - 'A') % 26 + 'A'));
else if (islower(target[num]))
target[num] = toupper(char(int(target[num] + k - 'a') % 26 + 'a'));
}
Note I've replaced your integer constants with their equivalent characters which makes the code much easier to understand.
Note you also have a bug in your first loop (target[j]) = ' ' should be (target[j]) == ' '.
Using all c++ has to offer you can reduce your code to:
#include <iostream>
#include <string>
#include <algorithm>
int main() {
std::string target = "mXLM";
char s = 'e';
int k = 7;
target.erase(std::remove(target.begin(), target.end(), ' '), target.end());
if (s == 'd') {
k = 26 - k;
}
std::string result;
std::transform(target.begin(), target.end(), std::back_inserter(result), [k](char in) {
if (isalpha(in)) {
char inputOffset = isupper(in) ? 'A' : 'a';
char outputOffset = isupper(in) ? 'a' : 'A';
return char(int(in + k - inputOffset) % 26 + outputOffset);
}
return in;
});
std::cout << result;
return 0;
}
When I input
0x123456789
I get incorrect outputs, I can't figure out why. At first I thought it was a max possible int value problem, but I changed my variables to unsigned long and the problem was still there.
#include <iostream>
using namespace std;
long htoi(char s[]);
int main()
{
cout << "Enter Hex \n";
char hexstring[20];
cin >> hexstring;
cout << htoi(hexstring) << "\n";
}
//Converts string to hex
long htoi(char s[])
{
int charsize = 0;
while (s[charsize] != '\0')
{
charsize++;
}
int base = 1;
unsigned long total = 0;
unsigned long multiplier = 1;
for (int i = charsize; i >= 0; i--)
{
if (s[i] == '0' || s[i] == 'x' || s[i] == 'X' || s[i] == '\0')
{
continue;
}
if ( (s[i] >= '0') && (s[i] <= '9') )
{
total = total + ((s[i] - '0') * multiplier);
multiplier = multiplier * 16UL;
continue;
}
if ((s[i] >= 'A') && (s[i] <= 'F'))
{
total = total + ((s[i] - '7') * multiplier); //'7' equals 55 in decimal, while 'A' equals 65
multiplier = multiplier * 16UL;
continue;
}
if ((s[i] >= 'a') && (s[i] <= 'f'))
{
total = total + ((s[i] - 'W') * multiplier); //W equals 87 in decimal, while 'a' equals 97
multiplier = multiplier * 16UL;
continue;
}
}
return total;
}
long probably is 32 bits on your computer as well. Try long long.
You need more than 32 bits to store that number. Your long type could well be as small as 32 bits.
Use a std::uint64_t instead. This is always a 64 bit unsigned type. If your compiler doesn't support that, use a long long. That must be at least 64 bits.
The idea follows the polynomial nature of a number. 123 is the same as
1*102 + 2*101 + 3*100
In other words, I had to multiply the first digit by ten two times. I had to multiply 2 by ten one time. And I multiplied the last digit by one. Again, reading from left to right:
Multiply zero by ten and add the 1 → 0*10+1 = 1.
Multiply that by ten and add the 2 → 1*10+2 = 12.
Multiply that by ten and add the 3 → 12*10+3 = 123.
We will do the same thing:
#include <cctype>
#include <ciso646>
#include <iostream>
using namespace std;
unsigned long long hextodec( const std::string& s )
{
unsigned long long result = 0;
for (char c : s)
{
result *= 16;
if (isdigit( c )) result |= c - '0';
else result |= toupper( c ) - 'A' + 10;
}
return result;
}
int main( int argc, char** argv )
{
cout << hextodec( argv[1] ) << "\n";
}
You may notice that the function is more than three lines. I did that for clarity. C++ idioms can make that loop a single line:
for (char c : s)
result = (result << 4) | (isdigit( c ) ? (c - '0') : (toupper( c ) - 'A' + 10));
You can also do validation if you like. What I have presented is not the only way to do the digit-to-value conversion. There exist other methods that are just as good (and some that are better).
I do hope this helps.
I found out what was happening, when I inputted "1234567890" it would skip over the '0' so I had to modify the code. The other problem was that long was indeed 32-bits, so I changed it to uint64_t as suggested by #Bathsheba. Here's the final working code.
#include <iostream>
using namespace std;
uint64_t htoi(char s[]);
int main()
{
char hexstring[20];
cin >> hexstring;
cout << htoi(hexstring) << "\n";
}
//Converts string to hex
uint64_t htoi(char s[])
{
int charsize = 0;
while (s[charsize] != '\0')
{
charsize++;
}
int base = 1;
uint64_t total = 0;
uint64_t multiplier = 1;
for (int i = charsize; i >= 0; i--)
{
if (s[i] == 'x' || s[i] == 'X' || s[i] == '\0')
{
continue;
}
if ( (s[i] >= '0') && (s[i] <= '9') )
{
total = total + ((uint64_t)(s[i] - '0') * multiplier);
multiplier = multiplier * 16;
continue;
}
if ((s[i] >= 'A') && (s[i] <= 'F'))
{
total = total + ((uint64_t)(s[i] - '7') * multiplier); //'7' equals 55 in decimal, while 'A' equals 65
multiplier = multiplier * 16;
continue;
}
if ((s[i] >= 'a') && (s[i] <= 'f'))
{
total = total + ((uint64_t)(s[i] - 'W') * multiplier); //W equals 87 in decimal, while 'a' equals 97
multiplier = multiplier * 16;
continue;
}
}
return total;
}
I'm trying to implement a function to add two overly large (let's say 1000 digit long) numbers stored in strings. I'm having problems with correct conversions so I can add numbers correctly.
So far, this is what I've done:
string addBegin (string low, string high, int diff)
{
for (int i = 0; i <= diff; i++)
low = "0" + low;
high = "0" + high;
cout << "low: " << low << "\nhigh: " << high << endl;
string result;
int sum, carry = 0;
for (int i = low.length()-1; i >= 0; i--)
{
sum = (int)low[i] + (int)high[i] + carry;
carry = 0;
if (sum > 9)
{
sum -= 10;
carry = 1;
}
result = to_string(sum) + result;
}
return result;
}
string add (string a, string b)
{
int diff = a.length() - b.length();
if (diff <= 0) return addBegin(a, b, abs(diff));
else return addBegin(b, a, diff);
}
int main (void)
{
string x = add("52","205");
cout << "result: " << x << endl;
return 0;
}
Output:
low: 0052
high: 0205 //the first zero is for potential carry
result: 87899293 //wrong, should be 0257
The result here is made of 4 numbers: 87, 89, 92 and 93. That is obviously wrong, I did some unwanted additions with ASCII values. Any ideas how to make this work? Or is there, by any chance, some ridiculously simple way to add two veeeeery long numbers?
sum = (int)low[i] + (int)high[i] + carry;
This adds the values of the character encodings in e.g. ASCII. You want to subtract '0' from the encoding to get the numeric value.
sum = low[i] - '0' + high[i] - '0' + carry;
Do not forget subtracting '0' from low[i] and high[i] when doing the math.
(int)low[i] is 0x30..0x39 for chars '0'..'9'.
A problem is that you use
sum = (int)low[i] + (int)high[i] + carry;
which should be
sum = low[i] - '0' + high[i] - '0' + carry;
I have been trying to carry out a conversion from CString that contains Hex string to a Byte array and have been
unsuccessful so far. I have looked on forums and none of them seem to help so far. Is there a function with just a few
lines of code to do this conversion?
My code:
BYTE abyData[8]; // BYTE = unsigned char
CString sByte = "0E00000000000400";
Expecting:
abyData[0] = 0x0E;
abyData[6] = 0x04; // etc.
You can simply gobble up two characters at a time:
unsigned int value(char c)
{
if (c >= '0' && c <= '9') { return c - '0'; }
if (c >= 'A' && c <= 'F') { return c - 'A' + 10; }
if (c >= 'a' && c <= 'f') { return c - 'a' + 10; }
return -1; // Error!
}
for (unsigned int i = 0; i != 8; ++i)
{
abyData[i] = value(sByte[2 * i]) * 16 + value(sByte[2 * i + 1]);
}
Of course 8 should be the size of your array, and you should ensure that the string is precisely twice as long. A checking version of this would make sure that each character is a valid hex digit and signal some type of error if that isn't the case.
How about something like this:
for (int i = 0; i < sizeof(abyData) && (i * 2) < sByte.GetLength(); i++)
{
char ch1 = sByte[i * 2];
char ch2 = sByte[i * 2 + 1];
int value = 0;
if (std::isdigit(ch1))
value += ch1 - '0';
else
value += (std::tolower(ch1) - 'a') + 10;
// That was the four high bits, so make them that
value <<= 4;
if (std::isdigit(ch2))
value += ch1 - '0';
else
value += (std::tolower(ch1) - 'a') + 10;
abyData[i] = value;
}
Note: The code above is not tested.
You could:
#include <stdint.h>
#include <sstream>
#include <iostream>
int main() {
unsigned char result[8];
std::stringstream ss;
ss << std::hex << "0E00000000000400";
ss >> *( reinterpret_cast<uint64_t *>( result ) );
std::cout << static_cast<int>( result[1] ) << std::endl;
}
however take care of memory management issues!!!
Plus the result is in the reverse order as you would expect, so:
result[0] = 0x00
result[1] = 0x04
...
result[7] = 0x0E