Please bear with me. I am new to C altogether, let alone Objective C. I am trying to do something that should be simple however its not working. I am scanning a string of numbers that also contains symbols. As the mini function runs through the input string it appends numbers to a new string until it comes across an operator (I'm writing a calculator in my own way as a learning exercise.) Right now I am just doing the beginning part and scanning the string and appending character. Here is my code:
char userInput[99];
NSMutableString *number = nil;
int i;
printf( "Please enter math: " );
scanf( "%s", userInput );
fpurge( stdin );
NSString *InputString = [NSString stringWithUTF8String:userInput];
for (i=0; i < [InputString length]; i++) {
char current = [InputString characterAtIndex:i];
if (isalnum(current)) {
[number appendString:[NSString stringWithCharacters:¤t length:1]];
NSLog(#"%# ", number);
}
}
For the life of me I can not seem to figure out why it keeps printing 2012-05-02 19:23:20.935 CALC[1447:403] (null) instead of the number value for each number it comes across. So for example if there are 5 numbers in the entered string it will print that 5 times.
You never initialized number--so when you call -appendString: on it, you're only appending to nil, and the result is just nil back. Try this for your second line:
NSMutableString *number = [NSMutableString string];
Now number is an empty string object, which is very different from being nil, which is no object at all.
Related
I have an iOS application that talks to a RedBearLab Arduino device. My code that I use to send an int via bluetooth from Arduino to iOS is as follows:
void sendMyInt(int myInt) {
char b[4];
String str;
str=String(myInt);
str.toCharArray(b,4);
for (int i; i < 3; i++) {
char toPrint = b[i];
ble_write(toPrint);
}
}
Here is my code on the receiving end:
-(void) bleDidReceiveData:(unsigned char *)data length:(int)length
{
NSData *d = [NSData dataWithBytes:data length:length];
NSLog([NSString stringWithFormat:#"%#",d]);
NSString *s = [[NSString alloc] initWithData:d encoding:NSUTF8StringEncoding];
const char* clearChar = "!";
if ([self.label.text isEqualToString:#"Label"]) {
self.label.text = #"";
}
else if ([s isEqualToString:[NSString stringWithUTF8String:clearChar]]) {
self.label.text = #"";
}
else {
NSString *store = self.label.text;
NSString *full = [NSString stringWithFormat:#"%#%#",store,s];
self.label.text = full;
}
}
The final else statement fires somewhat as expected, and a value of 233! is printed out to the label over and over again, getting longer each time eventually forming things like 233!233!233! etc. As you can see, I am using a character (!) sent over a function to clear the label, but it never clears. The integer is the ASCII code for the exclamation point:
void clearLabel() {
int clearString = 33;
char excalamtion = clearString;
ble_write(excalamtion);
}
Why would this not clear the label? I assume it has something to do with the clashing formats, but I'm not really too good at that even after reading some documentation. For the else if statement I also tried this
if ([s isEqualToString:#"!"])
but that didn't work out either... Any help would be appreciated.
EDIT:
I forgot to put in my loop code so you can see function calls. Here it is:
void loop()
{
if ( ble_connected() ) {
int a = 223;
sendMyInt(a);
delay(1000);
clearLabel();
delay(1000);
}
ble_do_events();
}
EDIT 2:
Based on a suggestion by #Duncan C , I have isolated the problem to the fact that the data is being sent as one packet to the iPhone. Upon printing out my generated string when the data is received, the string 233! is received all at once rather than individual chars of 2 3 3, and one second later the signal to clear, !. The data takes two seconds to appear on my phone, indicating that both delays are being used. I need a way to separate the 2 3 3 packet from the ! packet.
First off, this line:
NSLog([NSString stringWithFormat:#"%#",d]);
Is sort of pointless. The stringWithFormat serves no real purpose, since NSLog takes a format string anyway.
Use this instead:
NSLog(#"%#", d);
You should probably also log the contents of "s" once you convert your NSData to an NSString. That will help you figure out what's going on.
What is likely going on is that your string is coming in as "233!", all together, 4 bytes at a time (assuming that your integer is == 233).
Your string is unlikely to ever contain just "!". Instead, it will likely contain "233!" (4 characters.) I say likely because it depends on how the data is packetized into BLE. Something that short should be sent all in 1 BLE packet, so you should get the entire string together.
You could use the NSString method rangeOfString: to search for your "!" string, and if it contains an "!", clear your label, but that won't really do any good either. If you're sending "233!", then the iOS code will see the exclamation point in the string it receives and simply clear the label.
Or does your arduino project first send "233", then after some other event, send the "!". You didn't make that clear.
Another problem: What does the Arduino String class do if the integer is less than 1000, or less than 100, and doesn't require 3 or 4 characters to convert to a char array? What is stored in the unused bytes? You're always sending 4 characters, which is probably wrong.
Adding in another ble_do_events(); after calling the sendMyInt(); function causes the data to be transmit in two separate packets.
I'm wondering, is there a way to detect a character that takes up more than 1 index spot in an NSString? (like an emoji). I'm trying to implement a custom text view and when the user pushes delete, I need to know if I should delete only the previous one index spot or more.
Actually NSString use UTF-16.So it is quite difficult to work with characters which takes two UTF-16 charater(unichar) or more.But you can do with rangeOfComposedCharacterSequenceAtIndexto get range and than delete.
First find the last character index from string
NSUInteger lastCharIndex = [str length] - 1;
Than get the range of last character
NSRange lastCharRange = [str rangeOfComposedCharacterSequenceAtIndex: lastCharIndex];
Than delete with range from character (If it is of two UTF-16 than it deletes UTF-16)
deletedLastCharString = [str substringToIndex: lastCharRange.location];
You can use this method with any type of characters which takes any number of unichar
For one you could transform the string to a sequence of characters using [myString UTF8String] and you can then check if the character has its first bit set to one or zero. If its one then this is a UTF8 character and you can then check how many bytes are there to this character. Details about UTF8 can be found on Wikipedia - UTF8. Here is a simple example:
NSString *string = #"ČTest";
const char *str = [string UTF8String];
NSMutableString *ASCIIStr = [NSMutableString string];
for (int i = 0; i < strlen(str); ++i)
if (!(str[i] & 128))
[ASCIIStr appendFormat:#"%c", str[i]];
NSLog(#"%#", ASCIIStr); //Should contain only ASCII characters
I'm not needing any serious security, I just need to stop 11 year olds with plist editors from editing their number of coins in my game with ease.
I created a function that takes a string, for each unicode value of a character it raises this unicode value by 220 plus 14 times the character number that it is in the string.
Obviously this will fail (I think) if the string was like a million characters long because eventually you run out of unicode characters, but for all intents and purposes, this will only be used on strings of 20 characters and less.
Are there any unicode characters in this range that will not be stored to a plist or will be ignored by Apple's underlying code when I save the plist so that when I retrieve it and decrypt the character will be gone and I can't decrypt it?
+(NSString*)encryptString:(NSString*)theString {
NSMutableString *encryptedFinal = [[NSMutableString alloc] init];
for (int i = 0; i < theString.length; i++) {
unichar uniCharacter = [theString characterAtIndex:i];
uniCharacter += +220+(14*i);
[encryptedFinal appendFormat:#"%C", uniCharacter];
}
return encryptedFinal;
}
+(NSString*)decryptString:(NSString*)theString {
NSMutableString *decryptedFinal = [[NSMutableString alloc] init];
for (int i = 0; i < theString.length; i++) {
unichar uniCharacter = [theString characterAtIndex:i];
uniCharacter += +220+(14*i);
[decryptedFinal appendFormat:#"%C", uniCharacter];
}
return decryptedFinal;
}
It works for a range of a string of length 20 characters or less if you are encrypting one of the first 26+26+10+30 characters in the unicode index at any given point along the 20 character line. It probably works higher, I just didn't test it any higher.
This is the code I created to test it, all unicode characters were stored in an NSString and stayed valid for counting later.
int i = 0;
NSMutableString *encryptedFinal = [[NSMutableString alloc] init];
NSString *theString = #"a";
int j = 26+26+10+30;//letters + capital letters + numbers + 30 extra things like ?><.\]!#$
int f = 0;
int z = 0;
while (f < j) {
while (i < 220+220+(14*20)) {
unichar uniCharacter = [theString characterAtIndex:0];
uniCharacter += +f;
uniCharacter += +220+(14*i);
[encryptedFinal appendFormat:#"%C", uniCharacter];
i++;
}
z += i;
f++;
i = 0;
}
NSLog(#"%#", encryptedFinal);
NSLog(#"%i == %i?", z, encryptedFinal.length);
There are two thing that you can do:
Save the number of coins using NSData rather than using
NSNumber. Then use
NSData+AES
to encrypt it. You can even encrypt your entire .plist file to
ensure that no other fields are changed.
Security through obscurity. Just save the number of coins as an important sounding field. e.g.:Security Token Number. You can also create a bogus number of coins field whose value is ignored. Or maybe save the same value in both the fields and flag the user for cheating if the two values don't match.
I am trying to create an NSString object from a const unichar buffer where I don't know the length of the buffer.
I want to use the NSString stringWithCharacters: length: method to create the string (this seems to work), but please can you help me find out the length?
I have:
const unichar *c_emAdd = [... returns successfully from a C++ function...]
NSString *emAdd = [NSString stringWithCharacters:c_emAdd length = unicharLen];
Can anyone help me find out how to check what unicharLen is? I don't get this length passed back to me by the call to the C++ function, so I presume I'd need to iterate until I find a terminating character? Anyone have a code snippet to help? Thanks!
Is your char buffer null terminated?
Is it 16-bit unicode?
NSString *emAdd = [NSString stringWithFormat:#"%S", c_emAdd];
Your unichars should be null terminated so you when you reach two null bytes (a unichar = 0x0000) in the pointer you will know the length.
unsigned long long unistrlen(unichar *chars)
{
unsigned long long length = 0llu;
if(NULL == chars) return length;
while(NULL != chars[length])
length++;
return length;
}
//...
//Inside Some method or function
unichar chars[] = { 0x005A, 0x0065, 0x0062, 0x0072, 0x0061, 0x0000 };
NSString *string = [NSString stringWithCharacters:chars length:unistrlen(chars)];
NSLog(#"%#", string);
Or even simpler format with %S specifier
I have a binary file I've loaded using an NSData object. Is there a way to locate a sequence of characters, 'abcd' for example, within that binary data and return the offset without converting the entire file to a string? Seems like it should be a simple answer, but I'm not sure how to do it. Any ideas?
I'm doing this on iOS 3 so I don't have -rangeOfData:options:range: available.
I'm going to award this one to Sixteen Otto for suggesting strstr. I went and found the source code for the C function strstr and rewrote it to work on a fixed length Byte array--which incidentally is different from a char array as it is not null terminated. Here is the code I ended up with:
- (Byte*)offsetOfBytes:(Byte*)bytes inBuffer:(const Byte*)buffer ofLength:(int)len;
{
Byte *cp = bytes;
Byte *s1, *s2;
if ( !*buffer )
return bytes;
int i = 0;
for (i=0; i < len; ++i)
{
s1 = cp;
s2 = (Byte*)buffer;
while ( *s1 && *s2 && !(*s1-*s2) )
s1++, s2++;
if (!*s2)
return cp;
cp++;
}
return NULL;
}
This returns a pointer to the first occurrence of bytes, the thing I'm looking for, in buffer, the byte array that should contain bytes.
I call it like this:
// data is the NSData object
const Byte *bytes = [data bytes];
Byte* index = [self offsetOfBytes:tag inBuffer:bytes ofLength:[data length]];
Convert your substring to an NSData object, and search for those bytes in the larger NSData using rangeOfData:options:range:. Make sure that the string encodings match!
On iPhone, where that isn't available, you may have to do this yourself. The C function strstr() will give you a pointer to the first occurrence of a pattern within the buffer (as long as neither contain nulls!), but not the index. Here's a function that should do the job (but no promises, since I haven't tried actually running it...):
- (NSUInteger)indexOfData:(NSData*)needle inData:(NSData*)haystack
{
const void* needleBytes = [needle bytes];
const void* haystackBytes = [haystack bytes];
// walk the length of the buffer, looking for a byte that matches the start
// of the pattern; we can skip (|needle|-1) bytes at the end, since we can't
// have a match that's shorter than needle itself
for (NSUInteger i=0; i < [haystack length]-[needle length]+1; i++)
{
// walk needle's bytes while they still match the bytes of haystack
// starting at i; if we walk off the end of needle, we found a match
NSUInteger j=0;
while (j < [needle length] && needleBytes[j] == haystackBytes[i+j])
{
j++;
}
if (j == [needle length])
{
return i;
}
}
return NSNotFound;
}
This runs in something like O(nm), where n is the buffer length, and m is the size of the substring. It's written to work with NSData for two reasons: 1) that's what you seem to have in hand, and 2) those objects already encapsulate both the actual bytes, and the length of the buffer.
If you're using Snow Leopard, a convenient way is the new -rangeOfData:options:range: method in NSData that returns the range of the first occurrence of a piece of data. Otherwise, you can access the NSData's contents yourself using its -bytes method to perform your own search.
I had the same problem.
I solved it doing the other way round, compared to the suggestions.
first, I reformat the data (assume your NSData is stored in var rawFile) with:
NSString *ascii = [[NSString alloc] initWithData:rawFile encoding:NSAsciiStringEncoding];
Now, you can easily do string searches like 'abcd' or whatever you want using the NSScanner class and passing the ascii string to the scanner. Maybe this is not really efficient, but it works until the -rangeOfData method will be available for iPhone also.