Reputation: 9
I have a NSMutableString
with a bunch of floating point numbers.
I need to convert them to NSMutableArray
but in groups of 3:
0.015637 0.0205293 0.0270841 0.0157598 0.0202236 0.0272967 0.013217 0.0205293 0.0283439 0.0115028 0.0205293 0.0290539 0.0107803 0.0202236 0.0296187 -0.029892 0.0194995 0.0108798 -0.0299242 0.0191089 0.0108915 0.0243682 0.0194995 0.0204474 0.0307989 0.0205293 -0.00543068 0.0313996 0.0202236 0.00274711 -0.0157598 0.0202236 0.0272967 -0.0180789 0.0202236 0.0258193 -0.0182457 0.0194995 -0.0260576 -0.0182654 0.0191089 -0.0260857 -0.0134582 0.0191089
The numbers are all floating point values and there can be over 30 000 of them or more.
I have tried this but it's not working…
NSArray *contentarray = [content componentsSeparatedByString: @" "];
for(NSNumber * withfastenumeration in contentarray)
{
[XYZarray addObject: withfastenumeration];
}
Hi Guys,
I wanted to add a bit more information to this question since you guys have been so helpful. Okay so this is a COLLADA XML based project, and it involves vectors so hence the massive array of floating point numbers.
I got to the point where I am parsing with NSXMLParser and isolating the points. They are given however, in a blank format in the XML file as X, Y, Z in repetitive order, only separated by spaces.
I am writing a machining algorithm so I need these numbers in an array, but I need the array to look like:
X0.015637 Y0.0205293 Z0.0270841 X0.0157598 Y0.0202236 Z0.0272967
Once I have that, then I can manipulate all these numbers in a similar fashion.
Again, thanks for these solutions and Happy Holidays!
Upvotes: 1
Views: 838
Reputation: 6124
If I understand right you want to receive an array of strings and each string must contain 3 numbers?
Let's use regexp:
NSString *inputString = @"0.015637 0.0205293 0.0270841 0.0157598 0.0202236 0.0272967 0.013217 0.0205293 0.0283439 0.0115028 0.0205293 0.0290539 0.0107803 0.0202236 0.0296187 -0.029892 0.0194995 0.0108798 -0.0299242 0.0191089 0.0108915 0.0243682 0.0194995 0.0204474 0.0307989 0.0205293 -0.00543068 0.0313996 0.0202236 0.00274711 -0.0157598 0.0202236 0.0272967 -0.0180789 0.0202236 0.0258193 -0.0182457 0.0194995 -0.0260576 -0.0182654 0.0191089 -0.0260857 -0.0134582 0.0191089 0.0191089";
NSError *error;
// Creating regexp that will split input string to substring with 3 numbers
NSRegularExpression *regExp = [NSRegularExpression regularExpressionWithPattern:@"(([\\d\\.-]+\\s?){3})"
options:0
error:&error];
// TODO: Handle error if appear
//
NSArray *matches = [regExp matchesInString:inputString
options:0
range:NSMakeRange(0, [inputString length])];
NSMutableArray *result = [NSMutableArray new];
for (NSTextCheckingResult *match in matches) {
// Get the matching string
NSString *substring = [inputString substringWithRange:[match range]];
// Trim whitespace at the end
substring = [substring stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
[result addObject:substring];
}
Upvotes: 0
Reputation: 24041
what about this?
NSMutableString *_string = // your raw string as in your question...
NSLock *_lock = [[NSLock alloc] init];
NSMutableArray *_array = [NSMutableArray array];
[[_string componentsSeparatedByString:@" "] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([_lock tryLock]) [_array addObject:@([obj doubleValue])], [_lock unlock];
}];
that would be a better solution if you want to work with the numbers in group of 3 elegantly:
put these in the .h file:
typedef struct {
Float64 a;
Float64 b;
Float64 c;
} FloatNumbers;
static inline FloatNumbers FloatNumbersMake(Float64 a, Float64 b, Float64 c) {
FloatNumbers fn; fn.a = a; fn.b = b; fn.c = c; return fn;
}
static inline NSString * NSStringFromFloatNumbers(FloatNumbers fn) {
return [NSString stringWithFormat:@"{%f, %f, %f}", fn.a, fn.b, fn.c];
}
static inline FloatNumbers FloatNumbersFromString(NSString * string) {
@try {
NSArray *_array = [[string stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"{}"]] componentsSeparatedByString:@", "];
return FloatNumbersMake([[_array objectAtIndex:0] doubleValue], [[_array objectAtIndex:1] doubleValue], [[_array objectAtIndex:2] doubleValue]);
}
@catch (NSException *exception) {
return FloatNumbersMake(0.f, 0.f, 0.f);
}
}
and these into any methods of the .m file (where you'd like to parse the raw string):
NSMutableString *_string = // your raw string with the numbers...
NSError *_error;
NSLock *_lock = [[NSLock alloc] init];
NSMutableArray *_mutableArray = [NSMutableArray array];
NSRegularExpression *_regExp = [NSRegularExpression regularExpressionWithPattern:@"(([\\d\\.\\+-]+\\s?){0,3})" options:0 error:&_error];
if (!_error) {
[_regExp enumerateMatchesInString:_string options:NSMatchingReportProgress range:NSMakeRange(0, _string.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
FloatNumbers _floatNumbers = FloatNumbersMake(MAXFLOAT, MAXFLOAT, MAXFLOAT);
@try {
NSArray *_groupOfNumbers = [[_string substringWithRange:result.range] componentsSeparatedByString:@" "];
_floatNumbers.a = [[_groupOfNumbers objectAtIndex:0] doubleValue];
_floatNumbers.b = [[_groupOfNumbers objectAtIndex:1] doubleValue];
_floatNumbers.c = [[_groupOfNumbers objectAtIndex:2] doubleValue];
}
@catch (NSException *exception) {
}
@finally {
if ([_lock tryLock]) [_mutableArray addObject:NSStringFromFloatNumbers(_floatNumbers)], [_lock unlock];
*stop = (flags == NSMatchingHitEnd);
}
}];
} else {
NSLog(@"%@", _error);
}
the _mutableArray
has the numbers, each object is a group of 3; here is an example of how you can read back the desired group of 3 numbers from the array and you are able to work with the values after.
// reading the numbers back
FloatNumbers _secondGroupOf3Numbers = FloatNumbersFromString([_mutableArray objectAtIndex:1]);
NSLog(@"a : %f, b : %f, c : %f", _secondGroupOf3Numbers.a, _secondGroupOf3Numbers.b, _secondGroupOf3Numbers.c);
therefore that will log you the second group of 3 numbers, like:
a : 0.015760, b : 0.020224, c : 0.027297
(bear in mind: those are rounded values for the debug-console only, the float numbers are the same as they were parsed.)
Upvotes: 2
Reputation: 386038
componentsSeparatedByString:
returns an array of NSString
, not an array of NSNumber
. You need to write code to convert each component to a number. For example, you can send doubleValue
to each component to get back a double
, and then use @(...)
to wrap the double
in an NSNumber
.
NSArray *words = [content componentsSeparatedByString:@" "];
NSMutableArray *triples = [NSMutableArray arrayWithCapacity:words.count / 3];
for (NSUInteger i = 0, count = words.count; i < count; i += 3) {
NSArray *triple = @[
@([words[i+0] doubleValue]),
@([words[i+1] doubleValue]),
@([words[i+2] doubleValue])
];
[triples addObject:triple];
}
Note that -[NSString doubleValue]
doesn't do locale-aware parsing. If you need that, you'll need to use an NSScanner
or NSNumberFormatter
. Also, if you are having trouble with the memory used by the array of 30000+ substrings, use an NSScanner
to process the substrings one at a time without creating the big array.
Here's how you do it with NSScanner
:
NSScanner *scanner = [NSScanner scannerWithString:content];
// or use localizedScannerWithString: for locale-aware parsing
NSMutableArray *triples = [NSMutableArray arrayWithCapacity:words.count / 3];
double x, y, z;
while ([scanner scanDouble:&x] && [scanner scanDouble:&y] && [scanner scanDouble:&z]) {
NSArray *triple = @[ @(x), @(y), @(z) ];
[triples addObject:triple];
}
Upvotes: 3