Simplifying a function based on matching the pattern of a string - c++

Question: I'm new to C++ and after writing the following code seems like there should be a way to shorten it. Maybe by somehow matching the string? How would this be done?
The function takes a string message received via Serial port and sets the value of a particular element of the pinValues[] array depending on the message. The value that will be set is determined by the last character H or L just before the \n.
String pattern: (a number)(H or L)\n
Eg: message == "4H\n" will set the 5th element pinValues[4] to HIGH. The number at the start of the string can be 1 to 2 digits.
void setPinValues(String message) {
if( message == "1H\n" ) {
pinValues[1] = HIGH;
}
if( message == "1L\n" ) {
pinValues[1] = LOW;
}
if( message == "2H\n" ) {
pinValues[2] = HIGH;
}
if( message == "2L\n" ) {
pinValues[2] = LOW;
}
if( message == "3H\n" ) {
pinValues[3] = HIGH;
}
if( message == "3L\n" ) {
pinValues[3] = LOW;
}
if( message == "4H\n" ) {
pinValues[4] = HIGH;
}
if( message == "4L\n" ) {
pinValues[4] = LOW;
}
if( message == "5H\n" ) {
pinValues[5] = HIGH;
}
if( message == "5L\n" ) {
pinValues[5] = LOW;
}
if( message == "6H\n" ) {
pinValues[6] = HIGH;
}
if( message == "6L\n" ) {
pinValues[6] = LOW;
}
}

This is probably not the official "C++"-approved way of doing it, but you could do:
unsigned int pinNo = 0;
unsigned char level = 0;
int result = sscanf(message.c_str(), "%u%c", &pinNo, &level);
if (result < 2)
// it failed
if (pinNo > 6)
// bad data
levelVal = (level == 'H') ? HIGH : LOW;

I'd do some sanity checking on the string while extracting the key and value from the first two chars. If you don't need to sanity check the message, it could be as short as
void setPinValues(String message) {
pinValues[ message[0] - '0' ] = (message[1] == 'H') ? HIGH:LOW;
}
Although you may want to make that a little longer, i.e. check the string length, and that the 2 chars your checking are in the right range. i.e
void setPinValues(string message) {
if (
message.size() >= 2
and
message[0] >= '1' and message[0] <= '6'
and (message[1]=='H' or message[1]=='L')
) {
pinValues[ message[0] - '0' ] = (message[1] == 'H') ? HIGH:LOW;
}
}
EDIT: you could also extend that to checking two leading digits, i.e.
int n, off=0;
if ( s[off] <= '9' and s[off] >= '0')
{
n = s[off++] - '0';
}
if ( s[off] <= '9' and s[off] >= '0')
{
n = 10*n + s[off++] - '0';
}
if (off > 0 and (s[1]=='H' or s[1]=='L')) {
pinValues[ message[0] - '0' ] = (message[1] == 'H') ? HIGH:LOW;
}

Assuming String is actually a std::string or has an identical interface, and also assuming an ASCII-compatible character set...
void setPinValues(String message) {
const size_t sz = message.size();
// input validation, ignore the message if it doesn't fit the pattern
// you can remove this "if" block if the message has already been validated
if ( (sz < 3) || (sz > 4)
// note how message[0] will be checked twice if sz == 3
// once as message[0] and once as message[sz -3]
// but if sz == 4 we check message[0] and message[1]
|| (message[0] < '0') || (message[0] > '9')
|| (message[sz - 3] < '0') || (message[sz - 3] > '9')
|| ((message[sz - 2] != 'H') && (message[sz - 2] != 'L'))
|| (message[sz - 1] != '\n'))
return;
// convert the first or two characters to a number
int pinNumber = message[0] - '0';
if (sz == 4)
pinNumber = (pinNumber * 10) + (message[1] - '0');
// additional check to verify the pin number is in the correct range
if ((pinNumber < 1) || (pinNumber > 6))
return;
// apply
pinValues[pinNumber] = (message[sz - 2] == 'H' ? HIGH : LOW);
}

Related

run-length encoding is not working with big numbers

I have a assingment were I need to code and decode txt files, for example: hello how are you? has to be coded as hel2o how are you? and aaaaaaaaaajkle as a10jkle.
while ( ! invoer.eof ( ) ) {
if (kar >= '0' && kar <= '9') {
counter = kar-48;
while (counter > 1){
uitvoer.put(vorigeKar);
counter--;
}
}else if (kar == '/'){
kar = invoer.get();
uitvoer.put(kar);
}else{
uitvoer.put(kar);
}
vorigeKar = kar;
kar = invoer.get ( );
}
but the problem I have is if need to decode a12bhr, the answer is aaaaaaaaaaaabhr but I can't seem to get the 12 as number without problems, I also can't use any strings.
try to put a repeated character when next is not numeric or end of string.
For prepare this, it needs to make number by parsing string.
about this, I recommend you to find how to convert string to integer in real time at C++.
bool isNumeric(char ch) {
return '0' <= ch && ch <= '9';
}
string decode(const string& s) {
int counter = 0;
string result;
char prevCh;
for (int i = 0; i < s.length(); i++) {
if (isNumeric(s[i])) { // update counter
counter = counter * 10 + (s[i] - '0');
if (isNumeric(s[i + 1]) == false || i + 1 == s.length()) {
// now, put previous character stacked
while (counter-- > 1) {
result.push_back(prevCh);
}
counter = 0;
}
}
else {
result.push_back(s[i]);
prevCh = s[i];
}
}
return result;
}
now, decode("a12bhr3") returns aaaaaaaaaaaabhrrr. it works well.

Affine cipher decryption, output differs for upper case and lower case

I have the problem when decrypting a plaintext using Affine cipher.
Encryption works fine, but applying the same logic for decryption of lower case/upper case characters returns different output.
Here is the output:
Encrypted Message is : ulctkbsjarizqhypgxofwnevmd ULCTKBSJARIZQHYPGXOFWNEVMD
Decrypted Message is: opqrstuvwxyzabcdefghijklmn ABCDEFGHIJKLMNOPQRSTUVWXYZ
I suspect it has something to do with retrieving of ASCII values, can someone correct me?
Here is my code:
#include<bits/stdc++.h>
using namespace std;
//Key values of a and b
const int a = 17;
const int b = 20;
string encryptMessage(string plainText)
{
string cipher = "";
for (int i = 0; i < plainText.length(); i++)
{
if(plainText[i]!=' ')
{
if ((plainText[i] >= 'a' && plainText[i] <= 'z') || (plainText[i] >= 'A' && plainText[i] <= 'Z'))
{
if (plainText[i] >= 'a' && plainText[i] <= 'z')
{
cipher = cipher + (char) ((((a * (plainText[i]-'a') ) + b) % 26) + 'a');
}
else if (plainText[i] >= 'A' && plainText[i] <= 'Z')
{
cipher = cipher + (char) ((((a * (plainText[i]-'A') ) + b) % 26) + 'A');
}
}
else
{
cipher += plainText[i];
}
}
else
{
cipher += plainText[i];
}
}
return cipher;
}
string decryptCipher(string cipher)
{
string plainText = "";
int aInverse = 0;
int flag = 0;
for (int i = 0; i < 26; i++)
{
flag = (a * i) % 26;
if (flag == 1)
{
aInverse = i;
}
}
for (int i = 0; i < cipher.length(); i++)
{
if(cipher[i] != ' ')
{
if ((cipher[i] >= 'a' && cipher[i] <= 'z') || (cipher[i] >= 'A' && cipher[i] <= 'Z'))
{
if (cipher[i] >= 'a' && cipher[i] <= 'z')
{
plainText = plainText + (char) ((((aInverse * (cipher[i]+ 'a') ) - b) % 26) + 'a');
}
else if (cipher[i] >= 'A' && cipher[i] <= 'Z')
{
plainText = plainText + (char) (((aInverse * ((cipher[i]+'A' - b)) % 26)) + 'A');
}
}
else
{
plainText += cipher[i];
}
}
else
plainText += cipher[i];
}
return plainText;
}
//Driver Program
int main(void)
{
string msg = "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ";
//Calling encryption function
string cipherText = encryptMessage(msg);
cout << "Encrypted Message is : " << cipherText<<endl;
//Calling Decryption function
cout << "Decrypted Message is: " << decryptCipher(cipherText);
return 0;
}
I have been thinking about this for some time and, although I can't provide a complete explanation, I have a couple of 'observations' that may be useful, plus a 'cheat' workaround.
First, although you say you use "the same logic for decryption of lower case/upper case," a character-wise alignment of the code from each of your decryption blocks shows that this isn't quite true:
plainText = plainText + (char) ((((aInverse * (cipher[i]+ 'a') ) - b) % 26) + 'a'); // Lower case
plainText = plainText + (char) (((aInverse * ((cipher[i]+'A' - b)) % 26)) + 'A'); // Upper case
So, 'fixing' the lower case code to be exactly analogous to the (working) code for upper case (and removing redundant parentheses) gives this:
if (cipher[i] >= 'a' && cipher[i] <= 'z')
{
plainText = plainText + (char)( ( (aInverse * (cipher[i] + 'a' - b) ) % 26 ) + 'a' );
}
else if (cipher[i] >= 'A' && cipher[i] <= 'Z')
{
plainText = plainText + (char)( ( (aInverse * (cipher[i] + 'A' - b) ) % 26 ) + 'A' );
}
However, this doesn't actually resolve the issue (it just changes it slightly), as the output then is as follows:
Encrypted Message is : ulctkbsjarizqhypgxofwnevmd ULCTKBSJARIZQHYPGXOFWNEVMD
Decrypted Message is : qrstuvwxyzabcdefghijklmnop ABCDEFGHIJKLMNOPQRSTUVWXYZ
The problem here is that the lowercase values are all 'rotated' by the value 16 - which looks suspiciously close to the value for a. Also, note that, although a is used in the encryption formula, it is not used in your decryption.
So, I have come up with the following workaround, assuming that (for reasons yet to be deduced) when decoding upper case values, this 16 is somehow lost in the bit-representation of the ASCII values:
if ((cipher[i] >= 'a' && cipher[i] <= 'z') || (cipher[i] >= 'A' && cipher[i] <= 'Z'))
{
int offset = ((cipher[i] - 'A') / 26) ? a - 1 : 0;
if (cipher[i] >= 'a' && cipher[i] <= 'z') {
plainText = plainText + (char)( ( (aInverse * (cipher[i] + 'a' - b) - offset ) % 26 ) + 'a' );
}
else if (cipher[i] >= 'A' && cipher[i] <= 'Z') {
plainText = plainText + (char)( ( (aInverse * (cipher[i] + 'A' - b) - offset ) % 26 ) + 'A' );
}
}
Note that your code can be further simplified/clarified using functions provided by the standard library and removing some 'redundant' checks:
for (int i = 0; i < cipher.length(); i++) {
if (isalpha(cipher[i])) {
int offset = islower(cipher[i]) ? a - 1 : 0;
int letter = islower(cipher[i]) ? 'a' : 'A';
plainText = plainText + (char)(((aInverse * (cipher[i] + letter - b) - offset) % 26) + letter);
}
else {
plainText += cipher[i];
}
}

How to obtain the whole integers from file has strings and integers and store them into array in C++?

I want to obtain integers from file that has strings too, and store them into array to do some operation on them. the integers can be 1 or 12 or 234, so 3 digits. I am trying to do that but the output stops when I run the code
void GetNumFromFile (ifstream &file1, char & contents)
{
int digits[20];
file1.get(contents);
while(!file1.eof())
{
for (int n = 0; n < 10; n++)
{
if(('0' <= contents && contents <= '9') && ('0' >= contents+1 && contents+1 > '9'));
digits[n]=contents;
if(('0' <= contents && contents <= '9') && ('0' <= contents+1 && contents+1 < '9'));
digits[n]=contents;
if(('0' <= contents && contents <= '9') && ('0' <= contents+1 && contents+1 <= '9') && ('0' <= contents+2 && contents+2 < '9'));
digits[n]=contents;
}
continue;
}
for (int i = 0; i <= 20; i++)
{
cout << *(digits + i) << endl;
}
}
You have to deal with the number of digits of the number found:
int digits[20];
int i = 0;
short int aux[3]; // to format each digit of the numbers
ifstream file1("filepath");
char contents;
file1.get(contents); //first char
if (!file1.eof()) //test if you have only one char in the file
{
while (!file1.eof() && i < 20) // limit added to read only 20 numbers
{
if (contents <= '9' && contents >= '0') // if character is in number range
{
aux[0] = contents - '0'; // converting the char to the right integer
file1.get(contents);
if (contents <= '9' && contents >= '0') // if contents is number, continue on
{
aux[1] = contents - '0';
if (!file1.eof()) // if has mor char to read, continue on
{
file1.get(contents);
if (contents <= '9' && contents >= '0') // if is integer, continue on
{
aux[2] = contents - '0';
file1.get(contents); // will read same of last char if eof, but will have no effect at all
//aux[0] *= 100; // define houndred
//aux[1] *= 10; // define ten
digits[i++] = (aux[0] * 100) + (aux[1] * 10) + aux[2];
}
else
{
//aux[0] *= 10; // define ten
digits[i++] = (aux[0] * 10) + aux[1];
}
}
else
{
digits[i++] = (aux[0] * 10) + aux[1];
}
}
else
{
digits[i++] = aux[0];
}
}
}
}
else if (contents <= '9' && contents >= '0' && i < 20) // check if the only one char is number
{
digits[i++} = contents - '0';
}
If you want read an undefined size number, then you will have to allocate memory to format each digit of the numers with new (c++) or malloc(c/c++).
First observation: you iterate out of bounds of the array:
int digits[20];
for (int i = 0; i <= 20; i++)
20 elements and 21 iteration. That is an undefined behavior, so everything is possible here (if your program eventually gets here).
Next, you read from file once and then you have an infinite loop because the expression !file1.eof() is either true or false for the rest of the program run. Isn't that the reason of "output stops"?
The third finding: your if statements are useless because of the semicolon after the statement:
if(('0' <= contents && contents <= '9') && ('0' >= contents+1 && contents+1 > '9'));
digits[n]=contents;
You just assign digits[n]=contents; without any check.
I neither see any reason of providing a reference to char in the function. Why not to make it a local variable?
You will need first to add get() functionality inside the loop as well in order to reach end of file.
Forthmore try to add a while loop once a char was found to be an integer to continue in asking for the next character.
e.g.
int digits[20];
int i = 0;
ifstream file1("filepath");
char contents;
while (!file1.eof())
{
file1.get(contents); // get the next character
if (contents <= '9' && contents >= '0' && i < 20) // if character is in number range
{
digits[i++] = contents - '0'; // converting the chat to the right integer
file1.get(contents);
while (contents <= '9' && contents >= '0' && i < 20) // while is integer continue on
{
digits[i++] = contents - '0';
file1.get(contents);
}
}
}
// do other stuff here

How to identify i.e. distinquish textual content from other serialized representations?

Are there any algorithms that are could be used to distinguish or identify textual content from other serialized representations?
In my test case, I have at various locations of a file stored textual information such as (file-)names intermixed with other information such as serialized floating points. The textual content that I have has a leading 7-bit encoded length (similar to how BinaryWriter in .NET serializes strings). Ideally, I'd like to able to list all candidates that can be considered 'text'.
I have implemented a naive, rough and semi working algorithm. It goes like this: for every byte, decode a 7-bit encoded integer, evaluate if the content matches to human readable characters. However this approach gives a lot of false positives, duplicated entries. So my question is are there any algorithms that I could explore or alternatively how could I strengthen the conditions so that it matches the content I am looking for?.
bool read_string( char* buffer )
{
unsigned char num3;
int num = 0;
int num2 = 0;
do
{
if (num2 == 0x23)
{
return false;
}
//stream.read(reinterpret_cast<char*>( &num3), sizeof(num3));
num3 = *buffer;
num |= (num3 & 0x7f) << num2;
num2 += 7;
buffer++;
}
while ((num3 & 0x80) != 0);
if( num > 0 && num < 2048 )
{
bool is_false = false;
for( int i = 0; i < num; ++i )
{
bool ischaracter = ( buffer[i] >= 'a' && buffer[i] <= 'z' ) || ( buffer[i] >= 'A' && buffer[i] <= 'Z' ) || ( buffer[i] >= '0' && buffer[i] <= '9' ) || ( buffer[i] == '/' || buffer[i] == '\\' || buffer[i] == '.' || buffer[i] == ' ' || buffer[i] == '{' || buffer[i] == '}' || buffer[i] == ':' || buffer[i] == '_' );
if( ischaracter == false ) {
is_false = true;
}
}
if( !is_false )
{
std::string v;
for( int i = 0; i < num; ++i )
v.push_back( buffer[i] );
printf("%s\r\n", v.c_str() );
}
}
else
{
return false;
}
}

How should I approach a credit card number validation algorithm?

I'm writing a program to validate credit card numbers and I have to use Luhn's Algorithm. Let me say beforehand, that I have just started to learn to program (we covered loops like last week), so there a lot of things I am unfamiliar with. I am having trouble with one of my functions that checks the arithmetic. Basically, it has to double every second digit from right to left and add everything together. But if you double a number, like 5, and you get 10, then you will have to add 1+0=1 to the total sum instead of 10. That's the part I'm stuck on. How can I put that in a program?
Sample code so far:
int
doubleEvenSum(string creditCardNumber) {
int evenSum;
int countPosition;
int doublePosition;
int length;
length = creditCardNumber.length ();
countPosition = creditCardNumber.at(length - 2);
evenSum = 0;
while(countPosition>0) {
if ((2 * countPosition) < 10) {
doublePosition = 2 * countPosition;
}
else if ((2 * countPosition) > 9) {
???
}
evenSum = evenSum + doublePosition;
}
#include <stdio.h>
#include <string.h>
#include <ctype.h>
/*
return the Luhn (MOD10) checksum for a sequence of digits.
-1 is returned on error (a non-digit was in the sequence
*/
int mod10( char const* s)
{
int len = strlen(s);
int sum = 0;
int dbl = 0;
while (len) {
char digit;
int val;
--len;
digit = s[len];
if (!isdigit( (unsigned char) digit)) return -1; // non digit in the sequence
val = digit - '0'; // convert character to numeric value
if (dbl) {
// double the value
val *= 2;
// if the result is double-digits, add the digits together
if (val > 9) {
val = val - 10;
val = val + 1;
}
}
dbl = !dbl; // only double value every other time
sum += val;
}
return sum % 10;
}
Here is a different algorithm. I cut/pasted from a C# example; the second link discusses a number of optimization for Luhn.
Please study this example, and please run it through the debugger to study how the code behaves as it's executing. Understanding how code actually runs (as opposed to how you think it will run when you write it) is an essential skill. IMHO....
/*
* Validate credit card with Luhn Algorithm
*
* REFERENCES:
* - http://jlcoady.net/c-sharp/credit-card-validation-in-c-sharp
* - http://orb-of-knowledge.blogspot.com/2009/08/extremely-fast-luhn-function-for-c.html
*/
#include <stdio.h> // printf(), scanf(), etc
#include <string.h> // strlen (), etc
#include <ctype.h> // isdigit(), etc
#if !defined(FALSE)
#define FALSE 0
#define TRUE ~FALSE
#endif
/*
* type definitions (should go in separate header)
*/
enum CardType {
MASTERCARD=1, BANKCARD=2, VISA=3, AMEX=4, DISCOVER=5, DINERS=6, JCB=7
};
/*
* function prototypes (should also go in header)
*/
int luhn (int number[], int len);
bool validate (CardType cardType, char *cardNumber);
/*
* program main
*/
int
main (int argc, char *argv[])
{
char cc_number[80];
int cc_type;
for ( ;; ) {
printf ("Enter a credit card number and type (1, 2, 3, 4, 5. 6 or 7):\n");
printf (" MASTERCARD=1, BANKCARD=2, VISA=3, AMEX=4, DISCOVER=5, DINERS=6, JCB=7\n");
int iret = scanf ("%s %d", cc_number, &cc_type);
if (iret == 2)
break;
else
printf ("Incorrect input: please enter a valid CC# and CC type\n");
}
if (validate ((CardType)cc_type, cc_number))
printf ("Valid\n");
else
printf ("Invalid card type/number\n");
return 0;
}
/*
* validate card#
*/
bool
validate (CardType cardType, char *cardNumber)
{
// 16 or fewer digits?
int len = strlen(cardNumber);
if (strlen (cardNumber) > 16)
return false;
// number to validate
int number[16];
for(int i = 0; i < (int)strlen (cardNumber); i++) {
if(!isdigit(cardNumber[i]))
return FALSE;
number[i] = cardNumber[i] - '0';
}
// Validate based on card type, first if tests length, second tests prefix
switch(cardType) {
case MASTERCARD:
if(len != 16)
return FALSE;
if(number[0] != 5 || number[1] == 0 || number[1] > 5)
return FALSE;
break;
case BANKCARD:
if(len != 16)
return FALSE;
if(number[0] != 5 || number[1] != 6 || number[2] > 1)
return FALSE;
break;
case VISA:
if(len != 16 && len != 13)
return FALSE;
if(number[0] != 4)
return FALSE;
break;
case AMEX:
if(len != 15)
return FALSE;
if(number[0] != 3 || (number[1] != 4 && number[1] != 7))
return FALSE;
break;
case DISCOVER:
if(len != 16)
return FALSE;
if(number[0] != 6 || number[1] != 0 || number[2] != 1 || number[3] != 1)
return FALSE;
break;
case DINERS:
if(len != 14)
return FALSE;
if(number[0] != 3 || (number[1] != 0 && number[1] != 6 && number[1] != 8) || number[1] == 0 && number[2] > 5)
return FALSE;
break;
case JCB:
if(len != 16 && len != 15)
return FALSE;
if(number[0] != 3 || number[1] != 5)
return FALSE;
break;
default:
return FALSE;
}
int sum = luhn (number, len);
return (sum % 10 == 0);
}
// Use Luhn Algorithm to validate
int luhn (int number[], int len)
{
int sum = 0;
for(int i = len - 1; i >= 0; i--)
{
if(i % 2 == len % 2)
{
int n = number[i] * 2;
sum += (n / 10) + (n % 10);
}
else
sum += number[i];
}
return sum;
}
int luhnCardValidator(char cardNumbers[]) {
int sum = 0, nxtDigit, i;
for (i = 0; cardNumbers[i] != NULL_TERMINATOR ; i++) {
nxtDigit = cardNumbers[i] - START_OF_ASCII_NUMERIC;
if (i % 2 == 0)
nxtDigit = (nxtDigit > 4) ? (nxtDigit * 2 - 10) + 1 : nxtDigit * 2;
sum += nxtDigit;
}
return (sum % 10);
}
This:
... (nxtDigit > 4) ? (nxtDigit * 2 - 10) + 1 : ...
is the clever bit. If the digit is greater than 4, then the doubling will be 10 or more. In that case, you take the doubled number and subtract 10 which will give you the ones-digit then you add 1 (the tens-digit).
Just subtract 9 from the double of the number then you will equivalent of the sum of the digits.
For ex.
7= 7*2 = 14 = 1+4 = 5 OR 14-9 = 5
This is more efficient than writing code for adding both digits.