method for replacing comma between quotes in NSString, please check my one - objective-c

For parsing purposes it was necessary to replace commas inside quotas with space. I did not find and solution in NSString class and wrote this one.
It works, but I would like to know your opinion if there is more simple approach:
- (NSString *) replaceBetweenQuotesInString:(NSString*)line {
const char *buffer = [line UTF8String];
NSMutableIndexSet *evenIndexes = [NSMutableIndexSet indexSet];
NSMutableIndexSet *oddIndexes = [NSMutableIndexSet indexSet];
BOOL evenOdd = YES;
for (unsigned int i = 0; i < [line length]; i++) {
if (buffer[i] == '"'){
if (evenOdd)
[evenIndexes addIndex:i];
else
[oddIndexes addIndex:i];
evenOdd = !evenOdd;
}
}
if ([evenIndexes count] != [oddIndexes count] )
[evenIndexes removeIndex:[evenIndexes lastIndex]];
int totalRanges = (int) [evenIndexes count];
for (int i = 0; i < totalRanges; i++) {
NSRange range = NSMakeRange([evenIndexes firstIndex], [oddIndexes firstIndex] - [evenIndexes firstIndex]);
[evenIndexes removeIndex:[evenIndexes firstIndex]];
[oddIndexes removeIndex:[oddIndexes firstIndex]];
line = [line stringByReplacingOccurrencesOfString:#"," withString:#" " options:NSLiteralSearch range:range];
}
[evenIndexes removeAllIndexes];
[oddIndexes removeAllIndexes];
return line;
}

I have not tested this but since you do not seem to be concerned about escaped quotes:
NSMutableString* result = [[NSMutableString alloc] init];
NSArray* components = [line componentsSeparatedByString: #"\""];
for (int i = 0 ; i < [components count] ; ++i)
{
if (i % 2 == 0)
{
[result appendString: [components objectAtIndex: i]];
}
else
{
NSString* fixed = [[components objectAtIndex: i] stringByReplacingOccurrencesOfString: #","
withString: #" "];
[result appendFormat: #"\"%#\"", fixed];
}
}

Related

array index out of bounds problems

So I'm making a biginteger program, and I'm having a problem with adding two arrays that aren't the same length. The problem I'm having is with the add method. If I'm iterating through an array is there any way to test if element is out of bounds. I've tried testing if the element in a is equal to nil, but I still get the exception. Any help would be great thanks.
#import <Foundation/Foundation.h>
#import "MPInteger.h"
#implementation MPInteger
{
}
-(id) initWithString: (NSString *) x
{
self = [super init];
if (self) {
intString = [NSMutableArray array];
for (int i = 0; i < [x length]; i++) {
NSString *ch = [x substringWithRange:NSMakeRange(i, 1)];
[intString addObject:ch];
}
}
return self;
}
-(NSString *) description
{
return self.description;
}
- (MPInteger *) add: (MPInteger *) x {
NSMutableArray *a = self->intString;
NSMutableArray *b = x->intString;
NSMutableArray *c = [NSMutableArray array];
NSInteger arrayCount;
if (a < b) {
arrayCount = [b count];
} else {
arrayCount = [a count];
}
int num = 10;
int carry = 1;
NSNumber *total;
NSNumber *carrySum;
for (int i = 0; i < arrayCount; i++) {
if (a[i] == nil) {
total = #([b[i] intValue]);
[c addObject:total];
} else if (b[i] == nil) {
total = #([a[i] intValue]);
[c addObject:total];
} else {
total = #([a[i] intValue] + [b[i] intValue]);
[c addObject:total];
}
}
for (NSInteger j = [c count]-1; j >=0; j--) {
if ([c[j] intValue] >= num) {
total = #([c[j] intValue] - num);
carrySum = #([c[j-1] intValue] + carry);
[c replaceObjectAtIndex:j withObject:total];
[c replaceObjectAtIndex:j-1 withObject: carrySum];
}
}
NSString *str = [c componentsJoinedByString:#""];
NSLog(#"%#", str);
return x;
}
-(MPInteger *) multiply: (MPInteger *) x
{
NSMutableArray *a = self->intString;
NSMutableArray *b = x->intString;
NSMutableArray *c = [NSMutableArray array];
NSMutableArray *sum = [NSMutableArray array];
NSNumber *total;
NSNumber *carrySum;
int num = 10;
NSNumber *endZero = 0;
NSInteger bottomCount = [b count]-1;
while (bottomCount != -1) {
for (int i = 0; i < [a count]; i++) {
total = #([a[i] intValue] * [[b objectAtIndex:bottomCount] intValue]);
if (bottomCount == [b count] -1) {
[c addObject:total];
} else {
[c replaceObjectAtIndex:i withObject:total];
}
}
for (NSInteger j = [c count]-1; j>=0; j--) {
NSString *carry = [NSString stringWithFormat:#"%d", [c[j] intValue]];
NSString *carry2 = [carry substringToIndex:1];
int carryFinal = [carry2 intValue];
NSString *carry3 = [carry2 stringByAppendingString:#"0"];
int carry4 = [carry3 intValue];
if ([c[j] intValue] >= num) {
total = #([c[j] intValue] - carry4);
carrySum = #([c[j-1] intValue] + carryFinal);
[c replaceObjectAtIndex:j withObject:total];
[c replaceObjectAtIndex:j-1 withObject: carrySum];
} else {
if(j == 0) {
if (bottomCount == [b count] -1) {
bottomCount = bottomCount - 1;
NSString *str = [c componentsJoinedByString:#""];
[sum addObject: str];
} else {
[c addObject:#([endZero intValue])];
bottomCount = bottomCount - 1;
NSString *str = [c componentsJoinedByString:#""];
[sum addObject: str];
}
}
}
}
}
NSMutableArray *finalSum = [NSMutableArray array];
MPInteger *ele1;
MPInteger *ele2;
MPInteger *eleSum;
NSNumber *endZ= #(0);
[finalSum insertObject:endZ atIndex:0];
for (int k = 0; k < [sum count]; k++) {
NSString *str= [NSString stringWithFormat:#"%d", [sum[k] intValue]];
NSString *str2 = [NSString stringWithFormat:#"%d", [sum[k+1] intValue]];
ele1 = [[MPInteger alloc] initWithString:str];
ele2 = [[MPInteger alloc] initWithString:str2];
eleSum = [ele1 add: ele2];
NSLog(#"%#", eleSum);
}
NSLog(#"%#", sum);
return self;
}
Updated this
for (int i = 0; i < arrayCount; i++) {
if (a[i] == nil) {
total = #([b[i] intValue]);
[c addObject:total];
} else if (b[i] == nil) {
total = #([a[i] intValue]);
[c addObject:total];
} else {
total = #([a[i] intValue] + [b[i] intValue]);
[c addObject:total];
}
}
has now become:
NSMutableArray *c = a.count > b.count ? [a mutableCopy] : [b mutableCopy];
NSArray *shortestArray = a.count > b.count ? b : a;
[shortestArray enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(NSNumber *currentNumber, NSUInteger idx, BOOL *stop) {
c[idx] = #(currentNumber.integerValue + [c[idx] integerValue]);
NSLog(#"%#", c[idx]);
}];
What I think I need to do is every index that is in array a and not b or vise versa, is add beginning zeros, but I don't know how to do that.
I printed out what it does after each iteration and it gives:
2013-09-02 12:31:42.630 Asgn1[42471:303] 5
2013-09-02 12:31:42.632 Asgn1[42471:303] 3
2013-09-02 12:31:42.632 Asgn1[42471:303] 1
And a final answer of:
2013-09-02 12:31:42.633 Asgn1[42471:303] 353
For the code that is failing would it not be simpler to take a mutableCopy of the large array and then loop over the smaller array for the calculations?
Perhaps something like this:
NSMutableArray *c = a.count > b.count ? [a mutableCopy] : [b mutableCopy];
NSArray *shortestArray = a.count > b.count ? b : a;
[shortestArray enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(NSNumber *currentNumber, NSUInteger idx, BOOL *stop) {
c[idx] = #(currentNumber.integerValue + [c[idx] integerValue]);
}];

How to print the reverse of NSString in objective c without using componentsSeparatedByString method?

I want to make a method which gives reverse of string.suppose I pass a NSString "Welcome to Objective C" in method and that method return a reverse of string like "C Objective to Welcome" not "C evitcejbO ot emocleW" without the use of componentsSeparatedByString method.
Is it possible to do with Objective c..?
Please help.
You can enumerate strings by words.
NSString *string = #"Welcome to Objective-C!";
NSMutableArray *words = [NSMutableArray array];
[string enumerateLinguisticTagsInRange:NSMakeRange(0, [string length])
scheme:NSLinguisticTagSchemeTokenType
options:0
orthography:nil
usingBlock:^(NSString *tag, NSRange tokenRange, NSRange sentenceRange, BOOL *stop) {
[array addObject:[string substringWithRange:tokenRange]];
}];
NSMutableString *reverseString = [[NSMutableString alloc] init];
for (NSString *word in [words reverseObjectEnumerator]){
[reverse appendString:word];
}
NSLog(#"%#", reverseString);
This will print...
"!C-Objective to Welcome"
You can change the options to omit whitespaces and stuff...
I used below method for reversing string in iOS
- (NSString *)reverseString:(NSString *)stringToReverse
{
NSMutableString *reversedString = [NSMutableString stringWithCapacity:[stringToReverse length]];
[stringToReverse enumerateSubstringsInRange:NSMakeRange(0, [stringToReverse length])
options:(NSStringEnumerationReverse | NSStringEnumerationByComposedCharacterSequences)
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
[reversedString appendString:substring];
}];
return reversedString;
}
Sorry I misread your question earlier. I did it using a series of loops, my answer is messier than Fogmeister but I wanted to give it a shot to see if I could do it.
NSString *str = #"This is a test";
NSMutableArray *array = [[NSMutableArray alloc] init];
for(int i = 0; i < [str length]; i++)
{
char sTest = [str characterAtIndex:i];
if(sTest == ' ')
{
[array addObject:[NSNumber numberWithInt:i]];
}
}
NSInteger iNext = [[array objectAtIndex:[array count]-1] integerValue];
iNext+=1;
if(iNext < [str length])
{
[array addObject:[NSNumber numberWithInt:iNext]];
}
NSMutableArray *wordArray = [[NSMutableArray alloc] init];
for(int i = 0; i < [array count]; i++)
{
if (i == 0)
{
int num = [[array objectAtIndex:i] integerValue];
NSString *s = [[str substringFromIndex:0] substringToIndex:num];
[wordArray addObject:s];
}
else if(i == [array count]-1)
{
int prev = [[array objectAtIndex:i-1] integerValue]+1;
int num = [str length];
NSString *s = [[str substringToIndex:num] substringFromIndex:prev];
[wordArray addObject:s];
}
else
{
int prev = [[array objectAtIndex:i-1] integerValue]+1;
int num = [[array objectAtIndex:i] integerValue];
NSString *s = [[str substringToIndex:num] substringFromIndex:prev];
[wordArray addObject:s];
}
}
NSMutableArray *reverseArray = [[NSMutableArray alloc]init];
for(int i = [wordArray count]-1; i >= 0; i--)
{
[reverseArray addObject:[wordArray objectAtIndex:i]];
}
NSLog(#"%#", reverseArray);
Here i have done with replacing character with minimal number of looping. log(n/2).
NSString *string=#"Happy World";
NSInteger lenth=[string length];
NSInteger halfLength=[string length]/2;
for(int i=0;i<halfLength;i++)
{
NSString *leftString=[NSString stringWithFormat:#"%c",[string characterAtIndex:i]];
NSString *rightString=[NSString stringWithFormat:#"%c",[string characterAtIndex:(lenth-i-1)]];
string= [string stringByReplacingCharactersInRange:NSMakeRange(i, 1) withString:rightString];
string=[string stringByReplacingCharactersInRange:NSMakeRange((lenth-i-1), 1) withString:leftString];
}
NSLog(#"%#",string);
Try This , It's working perfect as per your expectation ,
Call Function :-
[self reversedString:#"iOS"];
Revers String Function :-
-(void)reversedString :(NSString *)reversStr
{ // reversStr is "iOS"
NSMutableString *reversedString = [NSMutableString string];
NSInteger charIndex = [reversStr length];
while (charIndex > 0) {
charIndex--;
NSRange subStrRange = NSMakeRange(charIndex, 1);
[reversedString appendString:[reversStr substringWithRange:subStrRange]];
}
NSLog(#"%#", reversedString); // outputs "SOi"
}
Hope So this is help for some one .
There is no API to do that, if that's what you are asking.
You can always iterate through the string looking for white spaces (or punctuation, it depends on your needs), identify the words and recompose your "reversed" message manually.

Split NSString with multiple delimiters?

For text bozo__foo!!bar.baz, how to split an NSString containing this into (bozo, foo, bar, baz)?
That is, separe it in components with strings (delimiters) __, !! and ..
You can split the strings using NSCharacterSet. Try this
NSString *test=#"bozo__foo!!bar.baz";
NSString *sep = #"_!.";
NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:sep];
NSArray *temp=[test componentsSeparatedByCharactersInSet:set];
NSLog(#"temp=%#",temp);
I'm aware that this question has already been answered but this is a way to separate strings using multiple strings. This is a category to NSString.
- (NSArray<NSString *> *)componentsSeparatedByStrings:(NSArray<NSString *> *)separators
{
NSMutableArray<NSString *> *components = [[NSMutableArray alloc] init];
unichar buffer[self.length + 1];
NSInteger currentOrigin = 0;
NSInteger currentLength = 0;
[self getCharacters:buffer];
for(NSInteger i = 0; i < self.length; i++)
{
unichar currentChar = buffer[i];
currentLength++;
for(NSInteger n = 0; n < separators.count; n++)
{
NSString *currentDivider = [separators objectAtIndex:n];
if(currentDivider.length == 0)
{
return #[self];
}
else if(currentDivider.length > 1)
{
BOOL goodMatch = NO;
for(NSInteger x = 0; x < currentDivider.length; x++)
{
unichar charInDivider = [currentDivider characterAtIndex:x];
if(charInDivider == currentChar)
{
goodMatch = YES;
}
else
{
goodMatch = NO;
break;
}
if(goodMatch == YES && ((x + 1) != currentDivider.length))
{
i++;
currentLength++;
currentChar = buffer[i];
}
}
if(goodMatch == YES)
{
NSRange newComponentRange = NSMakeRange(currentOrigin, (currentLength - currentDivider.length));
NSString *newComponent = [self substringWithRange:newComponentRange];
currentOrigin = (i + 1);
currentLength = 0;
[components addObject:newComponent];
NSLog(#"%#", components);
}
}
else // If current divider is only one character long.
{
if([currentDivider characterAtIndex:0] == currentChar)
{
NSRange newComponentRange = NSMakeRange(currentOrigin, (currentLength - 1));
NSString *newComponent = [self substringWithRange:newComponentRange];
currentOrigin = (i + 1);
currentLength = 0;
[components addObject:newComponent];
break;
}
}
}
// Handle the end of the string.
if((i + 1) == self.length)
{
NSRange newComponentRange = NSMakeRange(currentOrigin, currentLength);
NSString *newComponent = [self substringWithRange:newComponentRange];
currentOrigin = 0;
currentLength = 0;
[components addObject:newComponent];
}
}
return components;
}
Example: "ABCD__EFGHI__JKLMNOP-QRST.UV_WXYZ"
NSLog(#"%#", [test componentsSeparatedByStrings:#[#"__", #"-", #"."]]);
Log Result: "(ABCD, EFGHI, JKLMNOP, QRST, "UV_WXYZ")"
NSString *text = #"bozo__foo!!bar.baz";
NSArray *split1 = [text componentsSeparatedByString:#"__"];
NSArray *split2 = [[split1 lastObject] componentsSeparatedByString:#"!!"];
NSArray *split3 = [[split2 lastObject] componentsSeparatedByString:#"."];
NSLog(#"%#, %#, %#, %#", split1[0], split2[0], split3[0], split3[1]);
More functional solution is to apply -componentsSeparatedByString: recursively, for each component, which was derived during previous separator application:
NSString Category
- (NSMutableArray<NSString *> *)gvr_componentsSeparatedByStrings:(NSArray<NSString *> *)separators {
if (separators.count == 0) {
return [NSMutableArray arrayWithObject:self];
}
NSString *separator = [separators firstObject];
NSArray *reducedSeparators = [separators gvr_arrayByRemovingFirstObject];
NSArray *components = [self componentsSeparatedByString:separator];
NSMutableArray *result = [NSMutableArray new];
for (NSString *component in components) {
NSMutableArray *subResult = [component gvr_componentsSeparatedByStrings:reducedSeparators];
[result addObjectsFromArray:subResult];
}
return result;
}
NSArray Category
- (NSArray *)gvr_arrayByRemovingFirstObject {
NSMutableArray *result = [NSMutableArray new];
for (NSInteger i = 1; i < self.count; i++) {
[result addObject:self[i]];
}
return [result copy];
}
I solved it for my project by looking for the longest separator, replacing the others with this one, then do the separation on the only one left.
Try this:
NSString *test = #"bozo__foo!!bar.baz";
test = [test stringByReplacingOccurrencesOfString:#"!!" withString:#"__"];
test = [test stringByReplacingOccurrencesOfString:#"." withString:#"__"];
NSArray<NSString *> *parts = [test componentsSeparatedByString:#"__"];

How to merge paths (NSString) in xcode?

Imagine you have two paths.
http://myserver.com/path1/path2 + /path1/path2/cache/image1.jpg = http://myserver.com/path1/path2/cache/image1.jpg
Both path strings could have more or less path components.
So what I'm asking is how to find the equal part in the strings and then remove that part from one of the strings?
You have no idea whether the "equal" parts are really equal or not. It's not uncommon to have, eg, paths like .../part1/part1/part1/...
For the mechanics of dealing with the paths, though, NSString has some nice methods -- lastPathComponent, stringByAppendindPathComponent, pathComponents, pathWithComponents, etc.
What about this:
- (NSString *)mergeStringsPrefix:(NSString *)prefix suffix:(NSString *)suffix
{
NSString *string = [NSString stringWithFormat:#"%#", prefix];
NSArray *prefixComponents = [prefix pathComponents];
NSArray *suffixComponents = [suffix pathComponents];
if ([prefixComponents count] == 0) return [string retain];
int rootIndex = [suffixComponents indexOfObject:#"/"];
int index = 1;
if (rootIndex == NSNotFound || rootIndex != 0) index = 0;
int startIndex = [prefixComponents indexOfObject:[suffixComponents objectAtIndex:index]];
if (startIndex == NSNotFound) return nil;
if ([suffixComponents count] - index < [prefixComponents count] - startIndex) return nil;
// fing length and check merge compatability
BOOL equalParts = YES;
for (int i=startIndex; i<[prefixComponents count] && equalParts; i++, index++)
{
NSString *el1 = [prefixComponents objectAtIndex:i];
NSString *el2 = [suffixComponents objectAtIndex:index];
if ([el1 compare:el2] != NSOrderedSame) equalParts = NO;
}
if (!equalParts) return nil;
// merge
for (int i=index; i<[suffixComponents count]; i++)
{
string = [string stringByAppendingFormat:#"/%#", [suffixComponents objectAtIndex:i]];
}
return [string retain];
}
This should do for you:
NSString* path1 = #"http://myserver.com/path1/path2";
NSString* path2 = #"/path1/path2/cache/image1.jpg";
NSMutableArray* path1Components = [NSMutableArray arrayWithArray:[path1 componentsSeparatedByString:#"/"]];
NSMutableArray* path2Components = [NSMutableArray arrayWithArray:[path2 componentsSeparatedByString:#"/"]];
[path2Components removeObjectAtIndex:0];
if ([path1Components containsObject:[path2Components objectAtIndex:0]]) {
NSUInteger objectIndex = [path1Components indexOfObject:[path2Components objectAtIndex:0]];
[path1Components removeObjectsInRange:NSMakeRange(objectIndex, [path1Components count]-objectIndex)];
[path1Components addObjectsFromArray:path2Components];
NSString* mergedPath = [path1Components componentsJoinedByString:#"/"];
NSLog(#"%#",mergedPath);
}

Remove only first instance of a character from a list of characters

Here's what I want to do. I have 2 strings and I want to determine if one string is a permutation of another. I was thinking to simply remove the characters from string A from string B to determine if any characters are left. If no, then it passes.
However, I need to make sure that only 1 instance of each letter is removed (not all occurrences) unless there are multiple letters in the word.
An example:
String A: cant
String B: connect
Result: -o-nec-
Experimenting with NSString and NSScanner has yielded no results so far.
Hmmm, let's have a go:
NSString *stringA = #"cant";
NSString *stringB = #"connect";
NSUInteger length = [stringB length];
NSMutableCharacterSet *charsToRemove = [NSMutableCharacterSet characterSetWithCharactersInString:stringA];
unichar *buffer = calloc(length, sizeof(unichar));
[stringB getCharacters:buffer range:NSMakeRange(0, length)];
for (NSUInteger i = 0; i < length; i++)
{
if ([charsToRemove characterIsMember:buffer[i]])
{
[charsToRemove removeCharactersInRange:NSMakeRange(buffer[i], 1)];
buffer[i] = '-';
}
}
NSString *result = [NSString stringWithCharacters:buffer length:length];
free (buffer);
An inefficient yet simple way might be something like this (this is implemented as a category on NSString, but it could just as easily be a method or function taking two strings):
#implementation NSString(permutation)
- (BOOL)isPermutation:(NSString*)other
{
if( [self length] != [other length] ) return NO;
if( [self isEqualToString:other] ) return YES;
NSUInteger length = [self length];
NSCountedSet* set1 = [[[NSCountedSet alloc] initWithCapacity:length] autorelease];
NSCountedSet* set2 = [[[NSCountedSet alloc] initWithCapacity:length] autorelease];
for( int i = 0; i < length; i++ ) {
NSRange range = NSMakeRange(i, 1);
[set1 addObject:[self substringWithRange:range]];
[set2 addObject:[self substringWithRange:range]];
}
return [set1 isEqualTo:set2];
}
#end
This returns what your example asks for...
NSString* a = #"cant";
NSString* b = #"connect";
NSMutableString* mb = [NSMutableString stringWithString:b];
NSUInteger i;
for (i=0; i<[a length]; i++) {
NSString* theLetter = [a substringWithRange:NSMakeRange(i, 1)];
NSRange r = [mb rangeOfString:theLetter];
if (r.location != NSNotFound) {
[mb replaceCharactersInRange:r withString:#"-"];
}
}
NSLog(#"mb: %#", mb);
However, I wouldn't call that a permutation. To me a permutation would only hold true if all the characters from string "a" were contained by string "b". In your example, since the letter a in cant isn't in string b then I would say that cant is not a permutation of connect. With this definition I would use this:
-(BOOL)isString:(NSString*)firstString aPermutationOfString:(NSString*)secondString {
BOOL isPermutation = YES;
NSMutableString* mb = [NSMutableString stringWithString:secondString];
NSUInteger i;
for (i=0; i<[firstString length]; i++) {
NSString* theLetter = [firstString substringWithRange:NSMakeRange(i, 1)];
NSRange r = [mb rangeOfString:theLetter];
if (r.location != NSNotFound) {
[mb deleteCharactersInRange:r];
} else {
return NO;
}
}
return isPermutation;
}