I am trying to separate the values of a formatted string into an array. I have the string specifying format but cannot find a way to get the values of a formatted string given the format.
Here is the format string:
fmt=['%2i %2i %4i %2i %2i %2i %1i %11.7f %11.7f %12.5f %12.5f ' ...
'%5.2f %11.5f %5.2f %6.2f %2i %1i %9.5f %9.5f %3i\n'];
And here is an example of a formatted string that I'd like to separate:
5 27 2015 2 21 17 0 32.3788833 -64.6799500 6.16800 -0.12000 5.53 0.36000 5.40 6.03 4 4 -99.99999 -99.99999 999
Is there any way of doing this? If not, in objective-c can I replace consecutive spaces with one space and then separate with one space?
Hope this helps,
NSString *yourStr = #"5 27 2015 2 21 17 0 32.3788833 -64.6799500 6.16800 -0.12000 5.53 0.36000 5.40 6.03 4 4 -99.99999 -99.99999 999 ";
NSPredicate *nonEmptyValue = [NSPredicate predicateWithFormat:#"SELF != ''"];
NSArray *parts = [yourStr componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSArray *finalArr = [parts filteredArrayUsingPredicate:nonEmptyValue];
You can use NSString's componentsSeparatedByString: to convert your string into an NSArray.
Example:
NSString *string = #"5 27 2015 2 21 17 0 32.3788833 -64.6799500 6.16800 -0.12000 5.53 0.36000 5.40 6.03 4 4 -99.99999 -99.99999 999";
NSArray *array = [string componentsSeparatedByString:#" "];
P.S. Make sure you clean your string from leading/trailing spaces and convert multiple consecutive spaces into one single space character.
Related
Hello I am newbie to ios and objective c. I am working on a demo. In that I am having a for loop for adding values to NSMutableArray. Now this array will be added to NSMutableDictionary. Now inside this for loop i am having an if condition for checking string. I am adding objects to the array in "if" part and want to create a new Array when condition fail. I have tried as below, but in my Dictionary only one array saved. Can anyone help me where i have made mistake?
NSMutableArray *listingCommonArr,sectionTitles,eventDate;
int j=0;
NSString *dt;
NSMutableArray *sectionArray = [[NSMutableArray alloc]init];
sectionTitles = [orderedSet array];
NSLog(#"===listing common array---%d",[listingCommonArr count]);
sectionData = [[NSMutableDictionary alloc]init];
for(int i =0;i<[listingCommonArr count];i++)
{
dt = [[listingCommonArr objectAtIndex:i] objectForKey:#"start_date"];
NSLog(#"====my date at place===%# & my date is====%#",[sectionTitles objectAtIndex:j],dt);
for (int i =0; i < [listingCommonArr count]; i++) {
dt = [[listingCommonArr objectAtIndex:i] objectForKey:#"start_date"];
if ([(NSString *)[sectionTitles objectAtIndex:j] isEqualToString:dt]) {
[sectionArray addObject:listingCommonArr[i]];
//sectionData = #{dt : sectionArray}; // <-- PAY ATTENTION ON THIS LINE, PLEASE
//[sectionData setValue:sectionArray forKey:dt];
sectionData = [#{dt : sectionArray} mutableCopy];
} else {
[sectionData setObject:#"New value" forKey:#"string"];
sectionArray = [[NSMutableArray alloc]init];
j++;
}
}
NSLog(#"====my section DAta is==%#",sectionData);
}
errorTrace
-[__NSDictionaryI setObject:forKey:]: unrecognized selector sent to instance 0x7fc6547832a0
2015-12-18 19:39:41.387 iPhoneExploreCayman[41719:13822557] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSDictionaryI setObject:forKey:]: unrecognized selector sent to instance 0x7fc6547832a0'
*** First throw call stack:
(
0 CoreFoundation 0x000000010a551c65 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010a1e8bb7 objc_exception_throw + 45
2 CoreFoundation 0x000000010a5590ad -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x000000010a4af13c ___forwarding___ + 988
4 CoreFoundation 0x000000010a4aecd8 _CF_forwarding_prep_0 + 120
5 iPhoneExploreCayman 0x000000010604a48c -[iPhoneECListingView GetEventListingData:] + 1884
6 iPhoneExploreCayman 0x000000010605644b -[iPhoneECListingView EventListStart] + 1323
7 iPhoneExploreCayman 0x0000000106055a98 -[iPhoneECListingView EventClicked:] + 2312
8 UIKit 0x0000000108832d62 -[UIApplication sendAction:to:from:forEvent:] + 75
9 UIKit 0x000000010894450a -[UIControl _sendActionsForEvents:withEvent:] + 467
10 UIKit 0x00000001089438d9 -[UIControl touchesEnded:withEvent:] + 522
11 UIKit 0x000000010887f958 -[UIWindow _sendTouchesForEvent:] + 735
12 UIKit 0x0000000108880282 -[UIWindow sendEvent:] + 682
13 UIKit 0x0000000108846541 -[UIApplication sendEvent:] + 246
I'm highly confused about what you actually want to do here, but... after your comments I have completely updated my answer removing the previous assumptions about what actually is supposed to happen.
it seems to me you want(ed) to group a series of words by the first letter. you have posted a list of animals as example, so I worked with those.
you defined the expected output:
NSDictionary *_expectedOutput = #{#"A" :#[#"Affrican cat", #"Assian cat", #"Alsesian fox"], #"B" : #[#"Bear", #"Black Swan", #"Buffalo"], #"C" : #[#"Camel", #"Cockatoo"], #"D" : #[#"Dog", #"Donkey"], #"E" : #[#"Emu"], #"R" : #[#"Rhinoceros"], #"S" : #[#"Seagull"], #"T" : #[#"Tasmania Devil"], #"W" : #[#"Whale", #"Whale Shark", #"Wombat"]};
as you can see my input array is just an unsorted list of random names of animals from your sample output:
NSArray *_input = #[#"Whale Shark", #"Tasmania Devil", #"Affrican cat", #"Bear", #"Seagull", #"Black Swan", #"Whale", #"Wombat", #"Camel", #"Rhinoceros", #"Cockatoo", #"Buffalo", #"Assian cat", #"Alsesian fox", #"Emu"];
I'm working with that input array and I am going to group them by their first letter and build up the output:
NSMutableDictionary *_output = [NSMutableDictionary dictionary];
[[_input sortedArrayUsingSelector:#selector(compare:)] enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSString *_firstLetter = (obj.length > 0 ? [obj substringToIndex:1] : nil);
if (_firstLetter) {
NSMutableArray *_list = [_output valueForKey:_firstLetter];
if (_list == nil) {
_list = [NSMutableArray arrayWithObject:obj];
[_output setValue:_list forKey:_firstLetter];
} else {
[_list addObject:obj];
}
}
}];
that is pretty much it, if you'd log the _output, you can see on the console that is identical to your _expectedOutput collection.
you have sectionData = #{dt : sectionArray}; outside of the if section.
So on each iteration you dictionary will be recreated.
As I think you need the Mutable dictionary for sectionData, and move that string under "else" section
1 initialize mutable dictionary somewhere before the loop:
sectionData = [NSMutableDictionary new];
2 adding current array to dictionary must be under "else" block, also as I understand, you should create new sectionArray:
else
{
[sectionData setObject: sectionArray forKey:dt];
sectionArray = [[NSMutableArray alloc]init];
}
Every time you call sectionData = #{dt : sectionArray}; or anything sectionData is set other values are remove from dictionary and only last pair stays.(you are initializing dictionary every time you call setObject: forKey:)
If you want to create mutable dictionary and add objects to it you should do:
NSMutableDictionary *d2 = [NSMutableDictionary new];//sectionData in your case
[d2 addEntriesFromDictionary:#{#"b":#"c"}];//new key value pair added to d2
[d2 addEntriesFromDictionary:#{#"c":#"d"}];//new key value pair added to d2
[d2 addEntriesFromDictionary:#{#"d":#"e"}];//new key value pair added to d2
I am using http://aes.online-domain-tools.com to encrypt my NSString and what i get back from this is an array of unsigned char like this c2 84 6b 71 72 6d d2 e7 cd 0b a6 08 cd 85 c3 0c.
Then is use this to convert it into NSString in my code:
const unsigned char encrpytedAppIDbytes[] = {0xe5, 0x35, 0xdf, 0x72, 0x57, 0xaf, 0xf7, 0xe6, 0x1f, 0x6d, 0x51, 0x1d, 0x26, 0xe8, 0x5e, 0xa2};
NSData *appIDToDecrypt = [NSData dataWithBytes:encrpytedAppIDbytes length:sizeof(encrpytedAppIDbytes)];
NSString *decryptedAppID = [[NSString alloc] initWithData:[appIDToDecrypt AES128DecryptedDataWithKey:#"something"] encoding:NSUTF8StringEncoding];
if([decryptedAppID isEqualToString:#"Something"]){} // This fails even when i look at them in the debugger they are the same.
But when i am trying to decrypt it, its showing up as the same string but when i compare it with the same NSString hardcode to check if it is the same string it doesn't work.
This fails some authentication check i have in my app.
Please point anything wrong i am doing here.
Thanks,
Alright so after spending few hours with it i finally found the solutions which might not be optimal but works in my case.
It seems like after decryption, the string contains some other characters which are not visible in the debugger but when i am trying to check the length it shows greater than the number of characters in it which indicates that there is something wrong. For now what i have done is this :
const unsigned char nameBytes[] = {0xa6, 0xf0, 0xea, 0x36, 0x5f, 0x78, 0xb7, 0x52, 0x29, 0x6a, 0x67, 0xb7, 0xeb, 0x73, 0xd5, 0x14};
NSData *nameBytesData = [NSData dataWithBytes:nameBytes length:sizeof(nameBytes)];
NSString *nameBytesString = [[NSString alloc] initWithData:[nameBytesData AES128DecryptedDataWithKey:#"PaymentGateway"] encoding:NSUTF8StringEncoding];
NSCharacterSet * set = [[NSCharacterSet characterSetWithCharactersInString:#"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLKMNOPQRSTUVWXYZ0123456789"] invertedSet];
NSString *safeSearchString = [[nameBytesString componentsSeparatedByCharactersInSet:set] componentsJoinedByString:#""];
NSLog(#"length:%lu",(unsigned long)[safeSearchString length]);
NSLog(#"lengthActual:%lu",(unsigned long)[#"ashutosh" length]);
if ([safeSearchString isEqualToString:#"ashutosh"]) {
NSLog(#"Success");
}
NSLog(#"Decrypted:%#",nameBytesString);
The code above removes all the special characters and replaces it with #"" so the resulted string only has valid chars. For adding support to consider more chars as valid just add them to NSCharacterSet * set.
i am able to retrieve value from the peripheral as hex value and i need to convert as per my requirement.[24/12/14 11:37:00 am] sonali_phatak: I can see that i have received proper response.from 01117100352e36302e313100000000e55a
01 - 01-start byte
11 - 17(Dec) - length of responce packet
71 - response ID
00 - Ignore this byte
So now out of total length 17, first 4 bytes are header, last 2 bytes are CRC. We
need to read remaining 11 bytes and convert them to ASCII.
35 - 5
2e - .
36 - 6
30 - 0
2e - .
31 - 1
31 - 1
So Iam getting version number from watch as 5.60.11
But i need to show the above value 5.60.11 in string and print in console . how to convert it pleas help me
Please try this :
NSString *strOriginalHex= #"01117100352e36302e313100000000e55a";
NSString *strNewHexForVersion = [strOriginalHex substringWithRange:NSMakeRange(8, 14)];
NSLog(#"%#",[self stringFromHexString:strNewHexForVersion]);//5.60.11
- (NSString *)stringFromHexString:(NSString *)aStrHexString
{
// The hex codes should all be two characters.
if (([aStrHexString length] % 2) != 0)
return nil;
NSMutableString *aMutStrNewString = [NSMutableString string];
for (NSInteger i = 0; i < [aStrHexString length]; i += 2)
{
NSString *hex = [aStrHexString substringWithRange:NSMakeRange(i, 2)];
NSInteger decimalValue = 0;
sscanf([hex UTF8String], "%x", &decimalValue);
[aMutStrNewString appendFormat:#"%c", decimalValue];
}
return aMutStrNewString;
}
I would like to get all records for the current month, so I stack two predicates for first date of the month and last day of the month. Since I use CoreData the dates are stored actually as NSTimeInterval.
NSCalendar *calendar = [NSCalendar currentCalendar];
//Get beginning of current month
NSDateComponents *beginningOfCurrentMonthComponents = [calendar components:(NSEraCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:date];
[beginningOfCurrentMonthComponents setDay:1];
NSDate *beginningOfCurrentMonthDate = [calendar dateFromComponents:beginningOfCurrentMonthComponents];
//Set a single month to be added to the current month
NSDateComponents *oneMonth = [[NSDateComponents alloc] init];
[oneMonth setMonth:1];
//determine the last day of this month
NSDate *beginningOfNextMonthDate = [calendar dateByAddingComponents:oneMonth toDate:beginningOfCurrentMonthDate options:0];
NSMutableArray *parr = [NSMutableArray array];
[parr addObject:[NSPredicate predicateWithFormat:#"recordDate >= %d", [beginningOfCurrentMonthDate timeIntervalSince1970]]];
[parr addObject:[NSPredicate predicateWithFormat:#"recordDate < %d", [beginningOfNextMonthDate timeIntervalSince1970]]];
//Give me everything from beginning of this month until end of this month
NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:parr];
return [allRecords filteredArrayUsingPredicate:predicate];
Upon returning the filtered array, it crashes with this error message:
2013-10-25 19:09:39.702 [3556:a0b] -[__NSCFNumber timeIntervalSinceReferenceDate]: unrecognized selector sent to instance 0x8911440
2013-10-25 19:09:39.704 [3556:a0b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFNumber timeIntervalSinceReferenceDate]: unrecognized selector sent to instance 0x8911440'
*** First throw call stack:
(
0 CoreFoundation 0x01aa85e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x0182b8b6 objc_exception_throw + 44
2 CoreFoundation 0x01b45903 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275
3 CoreFoundation 0x01a9890b ___forwarding___ + 1019
4 CoreFoundation 0x01a984ee _CF_forwarding_prep_0 + 14
5 CoreFoundation 0x01a7e3e3 -[NSDate compare:] + 67
6 Foundation 0x014194fe -[NSComparisonPredicateOperator performPrimitiveOperationUsingObject:andObject:] + 408
7 Foundation 0x014b03de -[NSPredicateOperator performOperationUsingObject:andObject:] + 306
8 Foundation 0x014b016c -[NSComparisonPredicate evaluateWithObject:substitutionVariables:] + 347
9 Foundation 0x014299b6 -[NSCompoundPredicateOperator evaluatePredicates:withObject:substitutionVariables:] + 240
10 Foundation 0x01429845 -[NSCompoundPredicate evaluateWithObject:substitutionVariables:] + 294
11 Foundation 0x014b0009 -[NSPredicate evaluateWithObject:] + 48
12 Foundation 0x014aff89 _filterObjectsUsingPredicate + 418
13 Foundation 0x014afd42 -[NSArray(NSPredicateSupport) filteredArrayUsingPredicate:] + 328
I used this loop also to indicate that the recordDate truly exists within the array:
for (FTRecord *r in allRecords) {
NSLog(#"%f", [r recordDate]);
}
2013-10-25 19:09:35.860 [3556:a0b] 1380582000.000000
2013-10-25 19:09:36.556 [3556:a0b] 1380754800.000000
You chose the "Use scalar properties for primitive data types" option when
creating the managed object subclass, so that the recordDate is represented as
NSTimeInterval in the FTRecord class.
But in a predicate like "recordDate >= 123.45", the left-hand side is stored
as a NSKeyPathExpression, and that uses valueForKeyPath:#"recordDate" to access the property, which returns an NSDate object.
The right-hand side of that predicate is stored as NSConstantValueExpression
with a reference to an NSNumber object.
Therefore an NSDate is compared with an NSNumber, which leads exactly to the
exception that you got.
To fix the problem, you have to compare the property with an NSDate
(which is what #rmaddy initially suggested):
[parr addObject:[NSPredicate predicateWithFormat:#"recordDate >= %#", beginningOfCurrentMonthDate]];
[parr addObject:[NSPredicate predicateWithFormat:#"recordDate < %#", beginningOfNextMonthDate]];
NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:parr];
I tested this and it seems to produce the expected result.
Note however that Core Data uses timeIntervalSinceReferenceDate and
dateWithTimeIntervalSinceReferenceDate to convert between the scalar
values and NSDate, not timeIntervalSince1970.
For solution in Swift 3:
let date = NSDate()
let calender = NSCalendar.current
var beginningOfCurrentMonthComponents = calender.dateComponents([.year, .month, .day], from: date as Date)
beginningOfCurrentMonthComponents.day = 1
let beginningOfCurrentMonthDate = calender.date(from: beginningOfCurrentMonthComponents)
let beginningOfNextMonth = calender.date(byAdding: .month, value: 1, to: beginningOfCurrentMonthDate!)
let pred1 = NSPredicate(format: "date >= %#", beginningOfCurrentMonthDate! as NSDate)
let pred2 = NSPredicate(format: "date < %#", beginningOfNextMonth! as NSDate)
let predicate = NSCompoundPredicate.init(andPredicateWithSubpredicates: [pred1, pred2])
Will add timeIntervalSince1970 with in a predicate itself. It woul
NSPredicate* predicate = PREDICATE(#"(lastUpdatedTime == nil OR lastUpdatedTime.timeIntervalSince1970 <= %f)",currentDate.timeIntervalSince1970);
I try to read a large file in iOS using NSInputStream to separate the files line by newlines (I don't want to use componentsSeparatedByCharactersInSet as it uses too much memory).
But as not all lines seem to be UTF-8 encoded (as they can appear just as ASCII, same bytes) I often get the Incorrect NSStringEncoding value 0x0000 detected. Assuming NSASCIIStringEncoding. Will stop this compatiblity mapping behavior in the near future. warning.
My question is: Is there a way to surpress this warning by e.g. setting a compiler flag?
Furthermore: Is it save to append/concatenate two buffer reads, as reading from the byte stream, then converting the buffer to string and then appending the string could make the string corrupted?
Below an example method that demonstrates that the byte to string conversion will discard the first and second half of the UTF-8 character, as being invalid.
- (void)NSInputStreamTest {
uint8_t testString[] = {0xd0, 0x91}; // #"Б"
// Test 1: Read max 1 byte at a time of UTF-8 string
uint8_t buf1[1], buf2[1];
NSString *s1, *s2, *s3;
NSInteger c1, c2;
NSInputStream *inStream = [[NSInputStream alloc] initWithData:[[NSData alloc] initWithBytes:testString length:2]];
[inStream open];
c1 = [inStream read:buf1 maxLength:1];
s1 = [[NSString alloc] initWithBytes:buf1 length:1 encoding:NSUTF8StringEncoding];
NSLog(#"Test 1: Read %d byte(s): %#", c1, s1);
c2 = [inStream read:buf2 maxLength:1];
s2 = [[NSString alloc] initWithBytes:buf2 length:1 encoding:NSUTF8StringEncoding];
NSLog(#"Test 1: Read %d byte(s): %#", c2, s2);
s3 = [s1 stringByAppendingString:s2];
NSLog(#"Test 1: Concatenated: %#", s3);
[inStream close];
// Test 2: Read max 2 bytes at a time of UTF-8 string
uint8_t buf4[2];
NSString *s4;
NSInteger c4;
NSInputStream *inStream2 = [[NSInputStream alloc] initWithData:[[NSData alloc] initWithBytes:testString length:2]];
[inStream2 open];
c4 = [inStream2 read:buf4 maxLength:2];
s4 = [[NSString alloc] initWithBytes:buf4 length:2 encoding:NSUTF8StringEncoding];
NSLog(#"Test 2: Read %d byte(s): %#", c4, s4);
[inStream2 close];
}
Output:
2013-02-10 21:16:23.412 Test[11144:c07] Test 1: Read 1 byte(s): (null)
2013-02-10 21:16:23.413 Test[11144:c07] Test 1: Read 1 byte(s): (null)
2013-02-10 21:16:23.413 Test[11144:c07] Test 1: Concatenated: (null)
2013-02-10 21:16:23.413 Test[11144:c07] Test 2: Read 2 byte(s): Б
First of all, in line: s3 = [s1 stringByAppendingString:s2]; you are trying to concatenate to 'nil' values. The result would be 'nil' also. So, you may want to concatenate bytes instead of strings:
uint8_t buf3[2];
buf3[0] = buf1[0];
buf3[1] = buf2[0];
s3 = [[NSString alloc] initWithBytes:buf3 length:2 encoding:NSUTF8StringEncoding];
Output:
2015-11-06 12:57:40.304 Test[10803:883182] Test 1: Read 1 byte(s): (null)
2015-11-06 12:57:40.305 Test[10803:883182] Test 1: Read 1 byte(s): (null)
2015-11-06 12:57:40.305 Test[10803:883182] Test 1: Concatenated: Б
Secondary, length of UTF-8 character may lay in [1..6] bytes.
(1 byte) 0aaa aaaa //if symbol lays in 0x00 .. 0x7F (ASCII)
(2 bytes) 110x xxxx 10xx xxxx
(3 bytes) 1110 xxxx 10xx xxxx 10xx xxxx
(4 bytes) 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx
(5 bytes) 1111 10xx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx
(6 bytes) 1111 110x 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx
So, if you are intended to read from NSInputStream raw bytes and then translate them into UTF-8 NSString, you probably want to read byte by byte from NSInputStream until you will get valid string:
#define MAX_UTF8_BYTES 6
NSString *utf8String;
NSMutableData *_data = [[NSMutableData alloc] init]; //for easy 'appending' bytes
int bytes_read = 0;
while (!utf8String) {
if (bytes_read > MAX_UTF8_BYTES) {
NSLog(#"Can't decode input byte array into UTF8.");
return;
}
else {
uint8_t byte[1];
[_inputStream read:byte maxLength:1];
[_data appendBytes:byte length:1];
utf8String = [NSString stringWithUTF8String:[_data bytes]];
bytes_read++;
}
}
ASCII (and hence the newline character) is a subset of UTF-8, so there should not be any conflict.
It should be possible to divide your stream at the newline characters, as you would in a simple ASCII stream. Then you can convert each chunk ("line") into an NSString using UTF-8.
Are you sure the encoding errors are not real, i.e., that your stream may actually contain erroneous characters with respect to a UTF-8 encoding?
Edited to add from the comments:
This presumes that the lines consist of sufficiently few characters to keep a whole line in memory before converting from UTF-8.