isEqualToString not comparing properly - nsstring

I'm trying to do a string comparison on two strings stored in two different arrays. 90% of the time it works but the other 10% of the time it does not. In this case I am comparing town names.
Below is my code:
//setup of string comparison
NSString* string1 = [information from array 1];
NSString *string2 = [information from array 2];
//remove whitespace.
NSArray* string1sep = [string1 componentsSeparatedByCharactersInSet :[NSCharacterSet whitespaceCharacterSet]];
NSString* string1rw = [string1sep componentsJoinedByString:#""];
string1rw = [string1rw lowercaseString];
NSArray* string2sep = [string2 componentsSeparatedByCharactersInSet :[NSCharacterSet whitespaceCharacterSet]];
NSString* string2rw = [string2sep componentsJoinedByString:#""];
string2rw = [string2rw lowercaseString];
//compare strings
NSLog(#"%# (%u): %# (%u)", string1rw, [string1rw length], string2rw, [string2rw length]);
if([string1rw isEqualToString:string2rw]){
NSLog(#"Success");
}
my code is wrapped in a for loop that checks each element of the array. the output looks like so
-----------------------
Identifier 1
whangarei (9): whangarei (9)
whangarei (9): kaitaia (7)
whangarei (9): kerikeri (8)
whangarei (9): paruabay (8)
whangarei (9): kamo (4)
whangarei (9): tutukaka (8)
whangarei (9): auckland (8)
whangarei (9): kaiparacoast (12)
whangarei (9): paihia (6)
whangarei (9): hikurangi (9)
whangarei (9): hokianga (8)
whangarei (9): tba (3)
failure
-----------------------
Identifier 2
kaiparacoast (12): whangarei (9)
kaiparacoast (12): kaitaia (7)
kaiparacoast (12): kerikeri (8)
kaiparacoast (12): paruabay (8)
kaiparacoast (12): kamo (4)
kaiparacoast (12): tutukaka (8)
kaiparacoast (12): auckland (8)
kaiparacoast (12): kaiparacoast (12)
Success
The strings are both the same length, both spelled the same, both de-capitalized, both have white space removed. why does this work with one string but not another?
For peoples reference this is my original uncleaned code (bit harder to read)
- (BOOL) addToFilteredResults: (int) ofset{
int catCount = 0;
int citCount = 0;
NSLog(#"-----------------------");
NSLog(#"%#", [[CHARTeventsFull objectAtIndex:ofset]objectForKey:#"event"]);
for(NSString *cityCheck in eventCities){
if([[citySelected objectAtIndex:citCount] isEqual:[NSNumber numberWithBool:YES]]){
//setup of string comparison
NSArray* cityChecksep = [cityCheck componentsSeparatedByCharactersInSet :[NSCharacterSet whitespaceCharacterSet]];
NSString* cityCheckrw = [cityChecksep componentsJoinedByString:#""];
cityCheckrw = [cityCheckrw lowercaseString];
NSString *city = [[CHARTeventsFull objectAtIndex:ofset]objectForKey:#"town"];
NSArray* citysep = [city componentsSeparatedByCharactersInSet :[NSCharacterSet whitespaceCharacterSet]];
NSString* cityrw = [citysep componentsJoinedByString:#""];
cityrw = [cityrw lowercaseString];
//comparison
NSLog(#"%# (%u): %# (%u)", cityrw, [cityrw length], cityCheckrw, [cityCheckrw length]);
if([cityCheckrw isEqualToString:cityrw]){
//doing another comparison here this code can be ignored for this question
//----------------------------
for(NSString *categoryCheck in eventCatagories){
if([[catagorySelected objectAtIndex:catCount] isEqual:[NSNumber numberWithBool:YES]]){
NSArray *categoriesFromEvent = [[CHARTeventsFull objectAtIndex:ofset]objectForKey:#"categories"];
for (NSString *category in categoriesFromEvent) {
NSLog(#"%# : %#", category, categoryCheck);
if([categoryCheck isEqualToString:category]){
NSLog(#"Success");
return YES;
}
}
}
catCount++;
}
//---------------------------
}
}
citCount++;
}
NSLog(#"failure");
return NO;
}

You check if cityCheckrw is equal to cityrw, but you don't print "success" unless it makes it through your second check (the one you say we can ignore). It seems much more likely that the problem is in the second check or in the second for-loop than that two identical strings are not evaluating as equal. Does it still not print "success" when you move that NSLog to be right under the cityCheckrw/cityrw check?

I have sorted out the problem. I have abandoned using 'isEqualToString' and am now using predicates. no idea why 'isEqualToString' does not work 100% of the time but used basically the same structure with predicates and it worked perfectly. Here is a cleaned up version of what i did with predicates for those having the same problem
1 tier solution
this has
arrayOfObjects which never changes
filteredArrayOfObjects which changes when filtered
filterArray1 which has the filters stored in it
filterArray1Selected which has a BOOL indicating if the filter is active
and the code
//remove all objects from the filter array
[filteredArrayOfObjects removeAllObjects];
//set up compounder
NSMutableArray *compounder = [[NSMutableArray alloc] init];
int count = 0;
//go though the filter array and compound all the filters that are active
for(NSString *Check in FilterArray1){
if([[filterArray1Selected objectAtIndex:count] isEqual:[NSNumber numberWithBool:YES]]){
[compounder addObject:[NSPredicate predicateWithFormat:#"(filterName == %#)", Check]];
}
count++;
}
//compound the filters
NSPredicate *compounded = [NSCompoundPredicate orPredicateWithSubpredicates:compounder];
//filter the array
NSMutableArray *filteredArrayOfObjects = [[NSMutableArray alloc] initWithArray: [ArrayOfObjects filteredArrayUsingPredicate:compounded]];
have a 2 tier solution too but it gets messy

Related

The encryption won't decrypt

I was given an encrypted copy of the study guide here, but how do you decrypt and read it???
In a file called pa11.py write a method called decode(inputfile,outputfile). Decode should take two parameters - both of which are strings. The first should be the name of an encoded file (either helloworld.txt or superdupertopsecretstudyguide.txt or yet another file that I might use to test your code). The second should be the name of a file that you will use as an output file.
Your method should read in the contents of the inputfile and, using the scheme described in the hints.txt file above, decode the hidden message, writing to the outputfile as it goes (or all at once when it is done depending on what you decide to use).
The penny math lecture is here.
"""
Program: pennyMath.py
Author: CS 1510
Description: Calculates the penny math value of a string.
"""
# Get the input string
original = input("Enter a string to get its cost in penny math: ")
cost = 0
Go through each character in the input string
for char in original:
value = ord(char) #ord() gives us the encoded number!
if char>="a" and char<="z":
cost = cost+(value-96) #offset the value of ord by 96
elif char>="A" and char<="Z":
cost = cost+(value-64) #offset the value of ord by 64
print("The cost of",original,"is",cost)
Another hint: Don't forget about while loops...
Another hint: After letters -
skip ahead by their pennymath value positions + 2
After numbers - skip ahead by their number + 7 positions
After anything else - just skip ahead by 1 position
The issue I'm having in that I cant seem to get the coding right to decode the file it comes out looking the same. This is the current code I have been using. But once I try to decrypt the message it stays the same.
def pennycost(c):
if c >="a" and c <="z":
return ord(c)-96
elif c>="A" and c<="Z":
return ord(c)-64
def decryption(inputfile,outputfile):
with open(inputfile) as f:
fo = open(outputfile,"w")
count = 0
while True:
c = f.read(1)
if not c:
break;
if count > 0:
count = count -1;
continue
elif c.isalpha():
count = pennycost(c)
fo.write(c)
elif c.isdigit():
count = int(c)
fo.write(c)
else:
count = 6
fo.write(c)
fo.close()
inputfile = input("Please enter the input file name: ")
outputfile = input("Plese enter the output file name(EXISTING FILE WILL BE OVER WRITTEN!): ")
decryption(inputfile,outputfile)

DynamoDB ConditionExpression if resulting value is positive?

I'm writing an application that has a function for tipping points. I want to make a conditional update which is only executed if the resulting value of a user's wallet would be 0 or higher. If the value is negative the update should not happen.
The function works without the conditional expression but when I add it, it breaks.
ConditionExpression: 'teleUser.wallet.points -:a > -1',
In the above line :a is a passed in integer. I'll post the context below, but the above line is where my problem occurs.
The error returned is ValidationException: Invalid ConditionExpression: Syntax error; token: "-", near: "points -:a".
Full function for context:
function removeFromWallet(msg, amount) {
console.log("remove");
let params = {
TableName: tableName,
Key: {"id": msg.from.id},
UpdateExpression: 'set teleUser.wallet.points = teleUser.wallet.points -:a',
ExpressionAttributeValues:{
":a": parseInt(amount)
},
ConditionExpression: 'teleUser.wallet.points -:a > -1',
ReturnValues:"UPDATED_NEW"
};
docClient.update(params, function(err, data) {
if (err) {
console.log(err);
} else {
const { Items } = data;
console.log(data.Attributes.teleUser.wallet.points);
addToWallet(msg, amount);
}
});
}
You can't perform calculations in ConditionExpression (see grammar for ConditionExpression)
condition-expression ::=
operand comparator operand
| operand BETWEEN operand AND operand
| operand IN ( operand (',' operand (, ...) ))
| function
| condition AND condition
| condition OR condition
| NOT condition
| ( condition )
comparator ::=
=
| <>
| <
| <=
| >
| >=
function ::=
attribute_exists (path)
| attribute_not_exists (path)
| attribute_type (path, type)
| begins_with (path, substr)
| contains (path, operand)
| size (path)
You can perform calculations in ExpressionAttributeValues, but in this particular case you'll probably have to use teleUser.wallet.points >= :a since column values aren't available in ExpressionAttributeValues

Extracting record from big endian data

I have the following code for network protocol implementation. As the protocol is big endian, I wanted to use the Bit_Order attribute and High_Order_First value but it seems I made a mistake.
With Ada.Unchecked_Conversion;
with Ada.Text_IO; use Ada.Text_IO;
with System; use System;
procedure Bit_Extraction is
type Byte is range 0 .. (2**8)-1 with Size => 8;
type Command is (Read_Coils,
Read_Discrete_Inputs
) with Size => 7;
for Command use (Read_Coils => 1,
Read_Discrete_Inputs => 4);
type has_exception is new Boolean with Size => 1;
type Frame is record
Function_Code : Command;
Is_Exception : has_exception := False;
end record
with Pack => True,
Size => 8;
for Frame use
record
Function_Code at 0 range 0 .. 6;
Is_Exception at 0 range 7 .. 7;
end record;
for Frame'Bit_Order use High_Order_First;
for Frame'Scalar_Storage_Order use High_Order_First;
function To_Frame is new Ada.Unchecked_Conversion (Byte, Frame);
my_frame : Frame;
begin
my_frame := To_Frame (Byte'(16#32#)); -- Big endian version of 16#4#
Put_Line (Command'Image (my_frame.Function_Code)
& " "
& has_exception'Image (my_frame.Is_Exception));
end Bit_Extraction;
Compilation is ok but the result is
raised CONSTRAINT_ERROR : bit_extraction.adb:39 invalid data
What did I forget or misunderstand ?
UPDATE
The real record in fact is
type Frame is record
Transaction_Id : Transaction_Identifier;
Protocol_Id : Word := 0;
Frame_Length : Length;
Unit_Id : Unit_Identifier;
Function_Code : Command;
Is_Exception : Boolean := False;
end record with Size => 8 * 8, Pack => True;
for Frame use
record
Transaction_Id at 0 range 0 .. 15;
Protocol_Id at 2 range 0 .. 15;
Frame_Length at 4 range 0 .. 15;
Unit_id at 6 range 0 .. 7;
Function_Code at 7 range 0 .. 6;
Is_Exception at 7 range 7 .. 7;
end record;
Where Transaction_Identifier, Word and Length are 16-bit wide.
These ones are displayed correctly if I remove the Is_Exception field and extend Function_Code to 8 bits.
The dump of the frame to decode is as following:
00000000 00 01 00 00 00 09 11 03 06 02 2b 00 64 00 7f
So my only problem is really to extract the 8th bit of the last byte.
So,
for Frame use
record
Transaction_Id at 0 range 0 .. 15;
Protocol_Id at 2 range 0 .. 15;
Frame_Length at 4 range 0 .. 15;
Unit_id at 6 range 0 .. 7;
Function_Code at 7 range 0 .. 6;
Is_Exception at 7 range 7 .. 7;
end record;
It seems you want Is_Exception to be the the LSB of the last byte?
With for Frame'Bit_Order use System.High_Order_First; the LSB will be bit 7,
(also, 16#32# will never be -- Big endian version of 16#4#, the bit pattern just doesn't match)
It may be more intuitive and clear to specify all of your fields relative to the word they're in, rather than the byte:
Unit_ID at 6 range 0..7;
Function_Code at 6 range 8 .. 14;
Is_Exception at 6 range 15 .. 15;
Given the definition of Command above, the legal values for the last byte will then be:
2 -> READ_COILS FALSE
3 -> READ_COILS TRUE
8 -> READ_DISCRETE_INPUTS FALSE
9 -> READ_DISCRETE_INPUTS TRUE
BTW,
by applying your update to your original program, and adding/changing the following, you program works for me
add
with Interfaces;
add
type Byte_Array is array(1..8) of Byte with Pack;
change, since we don't know the definition
Transaction_ID : Interfaces.Unsigned_16;
Protocol_ID : Interfaces.Unsigned_16;
Frame_Length : Interfaces.Unsigned_16;
Unit_ID : Interfaces.Unsigned_8;
change
function To_Frame is new Ada.Unchecked_Conversion (Byte_Array, Frame);
change
my_frame := To_Frame (Byte_Array'(00, 01, 00, 00, 00, 09, 16#11#, 16#9#));
I finally found what was wrong.
In fact, the Modbus Ethernet Frame definition mentioned that, in case of exception, the returned code should be the function code plus 128 (0x80) (see explanation on Wikipedia). That's the reason why I wanted to represent it through a Boolean value but my representation clauses were wrong.
The correct clauses are these ones :
for Frame use
record
Transaction_Id at 0 range 0 .. 15;
Protocol_Id at 2 range 0 .. 15;
Frame_Length at 4 range 0 .. 15;
Unit_id at 6 range 0 .. 7;
Is_Exception at 6 range 8 .. 8;
Function_Code at 6 range 9 .. 15;
end record;
This way, the Modbus network protocol is correctly modelled (or not but at least, my code is working).
I really thank egilhh and simonwright for making me find what was wrong and explain the semantics behind the aspects.
Obviously, I don't know who reward :)
Your original record declaration works fine (GNAT complains about the Pack, warning: pragma Pack has no effect, no unplaced components). The problem is with working out the little-endian Byte.
---------------------------------
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | BE bit numbers
---------------------------------
| c c c c c c c | e |
---------------------------------
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | LE bit numbers
---------------------------------
so if you want the Command to be Read_Discrete_Inputs, the Byte needs to have BE bit 4 (LE bit 3) set i.e. LE 16#8#.
Take a look at this AdaCore post on bit order and byte order to see how they handle it. After reading that, you will probably find that the bit order of your frame value is really 16#08#, which probably is not what you are expecting.
Big Endian / Little Endian typically refers to Byte order rather than bit order, so when you see that Network protocols are Big Endian, they mean Byte order. Avoid setting Bit_Order for your records. In modern systems, you will almost never need that.
Your record is only one byte in size, so byte order won't matter for it by itself. Byte order comes into play when you have larger field values (>8 bits long).
The bit_order pragma doesn't reverse the order that the bits appear in memory. It simply defines whether the most significant bit (left most) will be logically referred to as zero (High_Order_First) or the least significant bit will be referred to as zero (Low_Order_First) when interpreting the First_Bit and Last_Bit offsets from the byte position in the representation clause. Keep in mind that these offsets are taken from the MSB or LSB of the scalar the record component belongs to AS A VALUE. So in order for the byte positions to carry the same meaning on a little endian CPU as they do on a big endian CPU (as well as the in memory representation of multibyte machine scalars, which exist when one or more record components with the same byte position have a last_bit value which exceeds the capacity of a single byte) then 'Scalar_Storage_Order must also be specified.

QT regularExpressions retrieve numbers

I've to split simple QStrings of the form "number number number",for example " 2323 432 1223".
The code i use is
QString line;
QRegularExpression re("(\\d+)");
QRegularExpressionMatch match;
while(!qtextstream.atEnd()){
line = qtextstream.readLine();
match = re.match(line);
std::cout<<"1= "<<match.captured(0).toUtf8().constData()<<std::endl;
std::cout<<"2= "<<match.captured(1).toUtf8().constData()<<std::endl;
std::cout<<"3= "<<match.captured(2).toUtf8().constData()<<std::endl;
}
if the first line being processed is like the example string i get
for the first while cycle output:
1= 2323
2= 2323
3=
what is wrong?
Your regex only matches 1 or more digits once with re.match. The first two values are Group 0 (the whole match) and Group 1 value (the value captured with a capturing group #1). Since there is no second capturing group in your pattern, match.captured(2) is empty.
You must use QRegularExpressionMatchIterator to get all matches from the current string:
QRegularExpressionMatchIterator i = re.globalMatch(line);
while (i.hasNext()) {
qDebug() << i.next().captured(1); // or i.next().captured(0) to see the whole match
}
Note that (\\d+) contains an unnecessary capturing group, since the whole match can be accessed, too. So, you may use re("\\d+") and then get the whole match with i.next().captured(0).
If the usage of regular expressions isn't mandatory, you could also use QString's split()-function.
QString str("2323 432 1223");
QStringList list = str.split(" ");
for(int i = 0; i < list.length(); i++){
qDebug() << list.at(i);
}

How can I extract the MCC and MNC from a PLMN?

I am running the AT command AT+KCELL to get cell information and it returns, amongst other things, a PLMN (Public Land and Mobile Network) - the description of this from the documentation is:
PLMN identifiers (3 bytes), made of MCC (Mobile Country Code), and MNC
(Mobile Network Code).
OK, that matches what Wikipedia says - in there is the MCC and MNC. Now what I don't understand is how do I extract the aforementioned MCC and MNC values?
Here is an example. I get back:
32f210
and I am told (though I am sceptical) that that should result in:
MNC: 1
MCC: 232
but I can't for the life of me work out how to get that result from the PLMN so how do I parse this?
Well, I have found this out and figured I would add an answer here in case there is some other unlucky soul who has to do this - the PDF called GSM Technical Specification (section 10.2.4) contains the answer, the relevant bit is:
PLMN Contents: Mobile Country Code (MCC) followed by the Mobile Network Code (MNC). Coding: according to TS GSM 04.08 [14].
If storage
for fewer than the maximum possible number n is required, the excess
bytes shall be set to 'FF'. For instance, using 246 for the MCC and 81
for the MNC and if this is the first and only PLMN, the contents reads
as follows: Bytes 1-3: '42' 'F6' '18' Bytes 4-6: 'FF' 'FF' 'FF' etc.
So I was wrong to be sceptical!
I need to read from the left swapping the digits around so the first two bytes would be the MCC so that would be 232f and the MNC would be 01 then I just discard the f and I have 232 and 1! Glad that one is sorted.
For example, in c# you can do it like this:
string plmn = "whatever the plmn is";
string mcc = new string(plmn.Substring(0, 2).Reverse().ToArray())
+ new string(plmn.Substring(2, 2).Reverse().ToArray())
.Replace('f', ' ')
.Trim();
string mnc = new string(plmn.Substring(4, 2).Reverse().ToArray())
.Replace('f', ' ')
.Trim();
Here is a java answer with bitwise operations:
public static String mcc(byte[] plmnId) {
if (plmnId == null || plmnId.length != 3)
throw new IllegalArgumentException(String.format("Wrong plmnid %s", Arrays.toString(plmnId)));
int a1 = plmnId[0] & 0x0F;
int a2 = (plmnId[0] & 0xF0) >> 4;
int a3 = plmnId[1] & 0x0F;
return "" + a1 + a2 + a3;
}
public static String mnc(byte[] plmnId) {
if (plmnId == null || plmnId.length != 3)
throw new IllegalArgumentException(String.format("Wrong plmnid %s", Arrays.toString(plmnId)));
int a1 = plmnId[2] & 0x0F;
int a2 = (plmnId[2] & 0xF0) >> 4;
int a3 = (plmnId[1] & 0xF0) >> 4;
if (a3 == 15)
return "" + a1 + a2;
else
return "" + a1 + a2 + a3;
}

Resources