Parsing NSMutableString By Number Of Instances - objective-c

I have an NSMutableString that contains a lot of data. A short example of it is:
MP3: name length album
MP3: name length album
MP3: name length album
MP3: name length album
Now, what I'm trying to accomplish is to parse the string to contain only the first 3 MP3 data sets. So once the fourth instance of "MP3:" is found, stop parsing.
I've tried multiple thing to accomplish this, but I've been staring at it too long and am starting to go goofy. If it was an array it would be simple but unfortunately it's a string. Does anyone know how to accomplish the logic behind this?
To add more clarity: I would still like the first the MP3's to appear. They will be different every time so I can't do a subStringToIndex.

To do this efficiently, assuming the input string is very long (containing thousands of lines after the first three), you need to avoid using componentsSeparatedByString:.
Instead, find the first three newlines in the string, by using rangeOfString: repeatedly.
NSString *input = #"MP3: line1\nMP3: line2\nMP3: line3\nMP3: line4\nMP3: line5\n";
NSUInteger lineStartLocation = 0;
NSUInteger inputLength = input.length;
for (int i = 0; i < 3; ++i) {
NSRange searchRange = NSMakeRange(lineStartLocation, inputLength - lineStartLocation);
NSRange newlineRange = [input rangeOfString:#"\n" options:0 range:searchRange];
if (newlineRange.location == NSNotFound) {
// Not enough lines in input!
break;
} else {
lineStartLocation = newlineRange.location + 1;
}
}
NSString *top3 = [input substringToIndex:lineStartLocation];
NSLog(#"top3 = %#", top3);

NSArray *lines = [data componentsSeparatedByString:#"\n"];
for (NSUInteger i = 0, count = 0; i < lines.count && count < 3; i++) {
NSString *line = lines[i];
NSRange range = [line rangeOfString:#"MP3:"];
if (range.location == 0 && range.length == #"MP3:".length) {
// parsing
count++;
}
}

NSString * stringToParse = #"MP3: hola MP3: pfff MP3: cosas MP3: hello";
NSArray * arrayStringParsed = [stringToParse componentsSeparatedByString:#"MP3:"];
And the results is and array:
<__NSArrayM 0x15fb2f80>(
,
hola ,
pfff ,
cosas ,
hello
)
First element doesn't have anything but the other 4 are parsed and you can work with them.

Related

Converting String to Character to Integer

I am trying to take a string (#"12345") and extractor each individual character and convert to it's decimal equivalent.
#"1" = 1
#"2" = 2
etc.
Here is what I have this far:
...
[self ArrayOrder:#"1234"];
...
-(void)ArrayOrder(Nsstring *)Directions
{
NSString *singleDirections = [[NSString alloc] init];
//Loop Starts Here
*singleDirection = [[Directions characterAtIndex:x] intValue];
//Loop ends here
}
I have been receiving type errors.
The problem with your code is that [Directions characterAtIndex:x] returns a unichar, which is a Unicode character.
Instead, you can use NSRange and substrings to get each number out of the string:
NSRange range;
range.length = 1;
for(int i = 0; i < Directions.length; i++) {
range.location = i;
NSString *s = [Directions substringWithRange:range];
int value = [s integerValue];
NSLog(#"value = %d", value);
}
Another approach would be to use / 10 and % 10 to get to each number from the string individually. Such as:
NSString* Directions = #"1234";
int value = [Directions intValue];
int single = 0;
while(value > 0) {
single = value % 10;
NSLog(#"value is %d", single);
value /= 10;
}
However, that goes through your string backwards.

Best way to split integers in Objective C

If I have this:
int toSplit = 208;
What's the best way to split it so I get:
2
0
8
Method would be like this
- (NSMutableArray *) toCharArray : (NSString *) str
{
NSMutableArray *characters = [[NSMutableArray alloc] initWithCapacity:[str length]];
for (int i=0; i < [str length]; i++)
{
NSString *ichar = [NSString stringWithFormat:#"%c", [str characterAtIndex:i]];
[characters addObject:ichar];
}
return characters;
}
do {
int digit = toSplit % 10;
toSplit /= 10;
printf(#"%i", digit);
} while (toSplit > 0);
I hope it's not a homework.
EDIT: it's backwards so it's not a valid answer... However, leaving it here because it can still be useful for others.
Sort it into a string then pull it apart. So like this:
int toSplit = 208;
NSString *string = [NSString stringWithFormat: #"%i", toSplit];
NSMutableString *splitApartString = [[NSMutableString alloc] init];
for (int i = 0; i < [string length]; i++) {
NSString *substring = [string substringFromIndex: i];
[splitApartString appendFormat: #"%#\n", substring];
}
NSLog(#"%#", splitApartString); //YAY!
So what this does, is puts this int into a string, splits it apart, then iterates through each character and gets a string out of that character. Then it appends that substring to a NEW string.
Another alternative, is instead of getting a substring just get the char and use the %c operator. Also if you take a look at this code you will see this output:
> 2
> 0
> 8
> // extra space here
You could just add a condition to check if i is the string length - 1 and not add a space or you could just remove the last character!
I'm not familiar with Objective-C syntax, but something like:
void split(int toSplit)
{
if (!toSplit)
{
return;
}
split(toSplit / 10);
int digit = toSplit % 10;
printf(#"%i", digit);
}

How do I iterate through an NSString in objective c?

How can iterate through an NSString object in Objective c whiling maintaining an index for the character I am currently at?
I want to increment the ASCII value of every third character by 3, and then print this incremented character in a label in my user interface.
Wasn't clear whether you just wanted to print the incremented characters or all. If the former, here's is how you would do it:
NSString *myString = #"myString";
NSMutableString *newString = [NSMutableString string];
for (int i = 0; i < [myString length]; i++)
{
int ascii = [myString characterAtIndex:i];
if (i % 3 == 0)
{
ascii++;
[newString appendFormat:#"%c",ascii];
}
}
myLabel.text = newString;
Will this do the trick?
NSString *incrementString(NSString *input)
{
const char *inputUTF8 = [input UTF8String]; // notice we get the buffers so that we don't have to deal with the overhead of making many message calls.
char *outputUTF8 = calloc(input.length + 1, sizeof(*outputUTF8));
for (int i = 0; i < input.length; i++)
{
outputUTF8[i] = i % 3 == 0 ? inputUTF8[i] + 3 : inputUTF8[i];
}
NSString *ret = [NSString stringWithUTF8String:outputUTF8];
free(outputUTF8); // remember to free the buffer when done!
return ret;
}

Problem with NSString and NSRange

I'm having a rather annoying problem here. See, I'm trying to break up a string that I get into individual characters and symbols. The string is always in the form of an equation, like "3x+4" or "x/7+5". I need to separate the string into an array of individual strings. For example, if I had the first equation, I would want to have an NSMutableArray that has "3", "x", "+", and "4". Here is the section of code that I use:
NSMutableArray* list = [[NSMutableArray alloc] initWithCapacity:10];
for (int i = 0; i < [self.equationToGuess length]; i++) {
NSRange range = {i, i};
NSString* string= [[NSString alloc] initWithString:[self.equationToGuess substringWithRange:range]];
[list addObject:string];
}
I've made sure to check if self.equationToGuess always contains an equation using the debugger, and it does. list is also able to get some of the objects, but the problem is that it just puts the last two characters in one shelf on the list. So if I have that "3x+4" equation, this chunk of code puts "3", "x", and "+4" into the code, and then it crashes because it goes beyond the length of the string. Does anyone know how to fix this?
The two values in NSRange are not the starting and ending index. Rather, the first is the starting index and the second is the length of the range. So instead you want your range to be
NSRange range = NSMakeRange(i, 1);
Let's do this with a bit more panache:
NSInteger numberOfCharacters = [self.equationToGuess length];
NSMutableArray *characterArray = [[NSMutableArray alloc] initWithCapacity:numberOfCharacters];
for (NSUInteger idx = 0; idx < numberOfCharacters; idx++) {
NSRange range = NSMakeRange(idx, 1);
[characterArray addObject:[self.equationToGuess substringWithRange:range]];
}
Edit
After a hearty helping of humble pie - this is still not the best way to do it: if your equation has multi-digit coefficients, they will be split up. Have you considered using NSScanner to split the string up instead?
you could also use an alternative solution by getting characters from you string , for that you will have to use the below function of NSString.
- (unichar)characterAtIndex:(NSUInteger)index
.
NSMutableArray* list = [[NSMutableArray alloc] initWithCapacity:10];
NSString* string;
for (int i = 0; i < [self.equationToGuess length]; i++)
{
string = [[NSString alloc] initWithFormat:#"%c",[self.equationToGuess characterAtIndex:i]];
[list addObject:string];
[string release];
string = nil ;
}
NSInteger numberOfCharacters = [self.equationToGuess length];
NSMutableArray *characterArray = [[NSMutableArray alloc] initWithCapacity:numberOfCharacters];
for (NSUInteger idx = 0; idx < numberOfCharacters; idx++) {
[characterArray addObject:[NSString stringWithFormat:#"%c", [self.equationToGuess characterAtIndex:idx]]];
}

How do I divide NSString into smaller words?

Greetings,
I am new to objective c, and I have the following issue:
I have a NSString:
"There are seven words in this phrase"
I want to divide this into 3 smaller strings (and each smaller string can be no longer than 12 characters in length) but must contain whole words separated by a space, so that I end up with:
String1 = "There are" //(length is 9 including space)
String2 = "seven words"// (length is 11)
String3 = "in this" //(length is 7), with the word "phrase" ignored as this would exceed the maximum length of 12..
Currently I am splitting my original array into an array with:
NSArray *piecesOfOriginalString = [originalString componentsSeparatedByString:#" "];
Then I have multiple "if" statements to sort out situations where there are 3 words, but I want to make this more extensible for any array up to 39 (13 characters * 3 line) letters, with any characters >40 being ignored. Is there an easy way to divide a string based on words or "phrases" up to a certain length (in this case, 12)?
Something similar to this? (Dry-code warning)
NSArray *piecesOfOriginalString = [originalString componentsSeparatedByString:#" "];
NSMutableArray *phrases = [NSMutableArray array];
NSString *chunk = nil;
NSString *lastchunk = nil;
int i, count = [piecesOfOriginalString count];
for (i = 0; i < count; i++) {
lastchunk = [[chunk copy] autorelease];
if (chunk) {
chunk = [chunk stringByAppendingString:[NSString stringWithFormat:#" %#", [piecesOfOriginalString objectAtIndex:i]]];
} else {
chunk = [[[piecesOfOriginalString objectAtIndex:i] copy] autorelease];
}
if ([chunk length] > 12) {
[phrases addObject:lastchunk];
chunk = nil;
}
if ([phrases count] == 3) {
break;
}
}
well, you can keep splitting the string as you're already doing, or you could check out whether NSScanner suits your needs. In any case, you're going to have to do the math yourself.
Thanks McLemore, that is really helpful! I will try this immediately. My current solution is very similar, but less refined, as I hard coded the loops and use individual variable to hold the sub strings (called them TopRow, MidRow, and BottomRow), that and the memory management issue is overlooked... :
int maxLength = 12; // max chars per line (in each string)
int j=0; // for looping, j is the counter for managing the words in the "for" loop
TopRow = nil; //1st string
MidRow = nil; //2nd string
//BottomRow = nil; //third row string (not implemented yet)
BOOL Row01done = NO; // if YES, then stop trying to fill row 1
BOOL Row02done = NO; // if YES, then stop trying to fill row 2
largeArray = #"Larger string with multiple words";
tempArray = [largeArray componentsSeparatedByString:#" "];
for (j=0; j<[tempArray count]; j=j+1) {
if (TopRow == nil) {
TopRow = [tempArray objectAtIndex:j];
}
else {
if (Row01done == YES) {
if (MidRow == nil) {
MidRow = [tempArray objectAtIndex:j];
}
else {
if (Row02done == YES) {
//row 3 stuff goes here... unless I can rewrite as iterative loop...
//will need to uncommend BottomRow = nil; above..
}
else {
if ([MidRow length] + [[tempArray objectAtIndex:j] length] < maxLength) {
MidRow = [MidRow stringByAppendingString:#" "];
MidRow = [MidRow stringByAppendingString:[tempArray objectAtIndex:j]];
}
else {
Row02done = YES;
//j=j-1; // uncomment once BottowRow loop is implemented
}
}
}
}
else {
if (([TopRow length] + [[tempArray objectAtIndex:j] length]) < maxLength) {
TopRow = [TopRow stringByAppendingString:#" "];
TopRow = [TopRow stringByAppendingString:[tempArray objectAtIndex:j]];
}
else {
Row01done = YES;
j=j-1; //end of loop without adding the string to TopRow, subtract 1 from j and start over inside Mid Row
}
}
}
}