Getting NSRange of string between quotations? - iphone

I have a string:
He said "hello mate" yesterday.
I want to get an NSRange from the first quotation to the last quotation. So I tried something like this:
NSRange openingRange = [title rangeOfString:#"\""];
NSRange closingRange = [title rangeOfString:#"\""];
NSRange textRange = NSMakeRange(openingRange.location, closingRange.location+1 - openingRange.location);
But I'm not sure how to make it distinguish between the first quote and the second quote. How would I do this?

You could use a regular expression for this:
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"([\"])(?:\\\\\\1|.)*?\\1" options:0 error:&error];
NSRange range = [regex rangeOfFirstMatchInString:myString options:0 range:NSRangeMake(0, [myString length]];
Don't forget to check for errors ;)

You can always use 'rangeOfString:options:range:' for the second one (starting after the 'location' of the first one).
Option 1
- (NSRange)rangeOfQuoteInString:(NSString *)str {
int firstMatch = [str rangeOfString:#"\""].location;
int secondMatch = [str rangeOfString:#"\"" options:0 range:NSMakeRange(firstMatch + 1, [str length] - firstMatch - 1)].location;
return NSMakeRange(firstMatch, secondMatch + 1 - firstMatch);
}
I hope this is right. Done on my phone at dinner. ;-)
One other thing, though, since range of string likely does a similar implementation, why not iterate the 'char' values in the string and look for matches #1 & #2? Could be as fast or faster.
Option 2
- (NSRange)rangeOfQuoteInString:(NSString *)str {
int firstMatch = -1;
int secondMatch = -1;
for (int i = 0; i < [str length]; i = i + 1) {
unichar c = [str characterAtIndex:i];
if (c == '"') {
if (firstMatch == -1) {
firstMatch = i;
} else {
secondMatch = i;
break;
}
}
}
if (firstMatch == -1 || secondMatch == -1) {
// No full quote was found
return NSMakeRange(NSNotFound, 0);
} else {
return NSMakeRange(firstMatch, secondMatch + 1 - firstMatch);
}
}

Related

how to get digits of a integer from NSString?

I am having a string like NSString *str = #"123".I want to fill the digits of this string into UIPickerView.But how to get the digits from this string?I added the following code
- (void)pickerView:(UIPickerView *)pickerView didSelectRow: (NSInteger)row inComponent:(NSInteger)component
{
int number = [str intValue];
if(component == 0)
{
}
else if(component == 1)
{
}
else
{
}
}
Please see this..
NSMutableArray *arrNumbers = [[NSMutableArray] alloc] initWithCapacity:[YOURSTRING length]];
for (i=0;i<[YOURSTRING length];i++)
{
  unichaar ch = [YOURSTRING characterAtIndex:i];
  NSLog(#"Processing charachter %c",ch);
  // If you really want
  [arrNumbers addObject:(id)ch];
}
Other solutions seem to be excessive, considering NSString is already an array of characters. More lightweight solution:
NSString *str = #"123";
for (int i = 0; i < [str length]; i++) {
int digit = [str characterAtIndex:i] - '0';
// do something with your digit
}
If you have it as a string you can just do
NSArray * digitStrings = [str componentsSeparatedByString:""];
And each element in the array would be a digit as a NSString.
not tested but you can give it a try, this is supposed to scan all numeric entries of your string.
-(NSArray*)getDigitsFromString:(NSString*)str{
NSMutableString *outpuString = [NSMutableString
stringWithCapacity:str.length];
NSScanner *scanner = [NSScanner scannerWithString:str];
NSCharacterSet *numbers = [NSCharacterSet
characterSetWithCharactersInString:#"0123456789"];
while ([scanner isAtEnd] == NO) {
NSString *buffer;
if ([scanner scanCharactersFromSet:numbers intoString:&buffer]) {
[outpuString appendString:buffer];
} else {
[scanner setScanLocation:([scanner scanLocation] + 1)];
}
}
NSArray * digitStr = [outpuString componentsSeparatedByString:#""];
return digitStr;
}
NSMutableArray * digit=[[NSMutableArray alloc]init];
NSString *string = #"123456";
for (int i=0;i<[string length]; i++) {
NSString * newString = [string substringWithRange:NSMakeRange(i, 1)];
[digit addObject:newString];
}
NSLog(#"String %# ", digit)
One more answer which addresses more the idea of the original question by solving the problem of separating an int into it's digits:
NSString *numberString = #"68243";
int result[numberString.length];
NSInteger number = [numberString integerValue];
int j = numberString.length - 1;
while (j >= 0)
{
int power = pow(10, j);
int rest = (number % power);
result[j] = (number - rest)/power;
number = rest;
j--;
}

how to add comma to string after every nth character in xcode

my problem is pretty simple. I assign a value to string variable in xcode which looks like this:
ARAMAUBEBABRBGCNDKDEEEFO
and I need it like this:
AR,AM,AU,BE,BA,BR,BG,CN,DK,DE,EE,FO
The length is different in each variable.
thanx in advance
This function is usefull for numbers that need coma every thousands... which is what I wanted, hope it helps.
//add comas to a a string...
//example1: #"5123" = #"5,123"
//example2: #"123" = #"123"
//example3: #"123123123" = #"123,123,123"
-(NSString*) addComasToStringEvery3chrsFromRightToLeft:(NSString*) myString{
NSMutableString *stringFormatted = [NSMutableString stringWithFormat:#"%#",myString];
for(NSInteger i=[stringFormatted length]-3;i>0;i=i-3) {
if (i>0) {
[stringFormatted insertString: #"," atIndex: i];
}
}
return stringFormatted;
}
Try this:
int num;
NSMutableString *string1 = [NSMutableString stringWithString: #"1234567890"];
num = [string1 length];
for(int i=3;i<=num+1;i++) {
[string1 insertString: #"," atIndex: i];
i+=3;
}
NSString *yourString; // the string you want to process
int len = 2; // the length
NSMutableString *str = [NSMutableString string];
int i = 0;
for (; i < [yourString length]; i+=len) {
NSRange range = NSMakeRange(i, len);
[str appendString:[yourString substringWithRange:range]];
[str appendString:#","];
}
if (i < [str length]-1) { // add remain part
[str appendString:[yourString substringFromIndex:i]];
}
// str now is what your want
This would work well when your string is not very large:
NSString * StringByInsertingStringEveryNCharacters(NSString * const pString,
NSString * const pStringToInsert,
const size_t n) {
NSMutableString * const s = pString.mutableCopy;
for (NSUInteger pos = n, advance = n + pStringToInsert.length; pos < s.length; pos += advance) {
[s insertString:pStringToInsert atIndex:pos];
}
return s.copy;
}
If the string is very large, you should favor to compose it without insertion (append-only).
(define your own error detection)

Find all locations of substring in NSString (not just first)

There is a substring that occurs in a string several times. I use rangeOfString, but it seems that it can only find the first location. How can I find all the locations of the substring?
NSString *subString1 = #"</content>";
NSString *subString2 = #"--\n";
NSRange range1 = [newresults rangeOfString:subString1];
NSRange range2 = [newresults rangeOfString:subString2];
int location1 = range1.location;
int location2 = range2.location;
NSLog(#"%i",location1);
NSLog(#"%i",location2);
You can use rangeOfString:options:range: and set the third argument to be beyond the range of the first occurrence. For example, you can do something like this:
NSRange searchRange = NSMakeRange(0,string.length);
NSRange foundRange;
while (searchRange.location < string.length) {
searchRange.length = string.length-searchRange.location;
foundRange = [string rangeOfString:substring options:0 range:searchRange];
if (foundRange.location != NSNotFound) {
// found an occurrence of the substring! do stuff here
searchRange.location = foundRange.location+foundRange.length;
} else {
// no more substring to find
break;
}
}
Swift 3.0
Find all locations of substring i
let text = "This is the text and i want to replace something"
let mutableAttributedString = NSMutableAttributedString(string: text)
var searchRange = NSRange(location: 0, length: text.characters.count)
var foundRange = NSRange()
while searchRange.location < text.characters.count {
searchRange.length = text.characters.count - searchRange.location
foundRange = (text as NSString).range(of: "i", options: NSString.CompareOptions.caseInsensitive, range: searchRange)
if foundRange.location != NSNotFound {
// found an occurrence of the substring! do stuff here
searchRange.location = foundRange.location + foundRange.length
mutableAttributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.red, range: foundRange)
}
else {
// no more substring to find
break
}
}
//Apply
textLabel.attributedText = mutableAttributedString;
And this output-
This is my solution. Basically, the algorithm traverses the string looking for substring matches and returns those matches in an array.
Since an NSRange is a struct it cannot be added to the array directly. By using NSValue, I can encode the match first and then add it to the array. To retrieve the range, I then decode the NSValue object to an NSRange.
#import <Foundation/Foundation.h>
NSRange makeRangeFromIndex(NSUInteger index, NSUInteger length) {
return NSMakeRange(index, length - index);
}
NSArray<NSValue *> * allLocationsOfStringMatchingSubstring(NSString *text, NSString *pattern) {
NSMutableArray *matchingRanges = [NSMutableArray new];
NSUInteger textLength = text.length;
NSRange match = makeRangeFromIndex(0, textLength);
while(match.location != NSNotFound) {
match = [text rangeOfString:pattern options:0L range:match];
if (match.location != NSNotFound) {
NSValue *value = [NSValue value:&match withObjCType:#encode(NSRange)];
[matchingRanges addObject:value];
match = makeRangeFromIndex(match.location + 1, textLength);
}
}
return [matchingRanges copy];
}
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSString *text = #"TATACCATGGGCCATCATCATCATCATCATCATCATCATCATCACAG";
NSString *pattern = #"CAT";
NSArray<NSValue *> *matches = allLocationsOfStringMatchingSubstring(text, pattern);
NSLog(#"Text: %#", text);
NSLog(#"Pattern: %#", pattern);
NSLog(#"Number of matches found: %li", matches.count);
[matches enumerateObjectsUsingBlock:^(NSValue *obj, NSUInteger idx, BOOL *stop) {
NSRange match;
[obj getValue:&match];
NSLog(#" Match found at index: %li", match.location);
}];
}
return 0;
}
Passing nil to [string rangeOfString:substring options:nil range:searchRange]; shows a warning.
To get rid of the warning, put in an enum from this group
enum {
NSCaseInsensitiveSearch = 1,
NSLiteralSearch = 2,
NSBackwardsSearch = 4,
NSAnchoredSearch = 8,
NSNumericSearch = 64,
NSDiacriticInsensitiveSearch = 128,
NSWidthInsensitiveSearch = 256,
NSForcedOrderingSearch = 512,
NSRegularExpressionSearch = 1024
};
https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/index.html#//apple_ref/doc/constant_group/Search_and_Comparison_Options
Here is a version in Swift 2.2 of PengOne's answer with input from kevinlawler and Gibtang
Note: string and substring are of type NSString
let fullStringLength = (string as String).characters.count
var searchRange = NSMakeRange(0, fullStringLength)
while searchRange.location < fullStringLength {
searchRange.length = fullStringLength - searchRange.location
let foundRange = string.rangeOfString(substring as String, options: .CaseInsensitiveSearch, range: searchRange)
if foundRange.location != NSNotFound {
// found an occurrence of the substring! do stuff here
searchRange.location = foundRange.location + 1
} else {
// no more strings to find
break
}
}
I suggest using regular expression because it's a more declarative way and has fewer lines of code to write.
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"%#" options:nil error:nil];
NSString *toSearchStr = #"12312 %# Text %# asdsa %#";
__block int occurs = 0;
[regex enumerateMatchesInString:toSearchStr options:0 range:NSMakeRange(0, toSearchStr.length) usingBlock:^(NSTextCheckingResult * _Nullable result, NSMatchingFlags flags, BOOL * _Nonnull stop) {
occurs++;
}];
// occurs == 3

NSString range of string at occurrence

i'm trying to build a function that will tell me the range of a string at an occurrence.
For example if I had the string "hello, hello, hello", I want to know the range of hello at it's, lets say, third occurrence.
I've tried building this simple function, but it doesn't work.
Note - the top functions were constructed at an earlier date and work fine.
Any help appreciated.
- (NSString *)stringByTrimmingString:(NSString *)stringToTrim toChar:(NSUInteger)toCharacterIndex {
if (toCharacterIndex > [stringToTrim length]) return #"";
NSString *devString = [[[NSString alloc] init] autorelease];
for (int i = 0; i <= toCharacterIndex; i++) {
devString = [NSString stringWithFormat:#"%#%#", devString, [NSString stringWithFormat:#"%c", [stringToTrim characterAtIndex:(i-1)]]];
}
return devString;
[devString release];
}
- (NSString *)stringByTrimmingString:(NSString *)stringToTrim fromChar:(NSUInteger)fromCharacterIndex {
if (fromCharacterIndex > [stringToTrim length]) return #"";
NSString *devString = [[[NSString alloc] init] autorelease];
for (int i = (fromCharacterIndex+1); i <= [stringToTrim length]; i++) {
devString = [NSString stringWithFormat:#"%#%#", devString, [NSString stringWithFormat:#"%c", [stringToTrim characterAtIndex:(i-1)]]];
}
return devString;
[devString release];
}
- (NSRange)rangeOfString:(NSString *)substring inString:(NSString *)string atOccurence:(int)occurence {
NSString *trimmedString = [inString copy]; //We start with the whole string.
NSUInteger len, loc, oldLength;
len = 0;
loc = 0;
NSRange tempRange = [string rangeOfString:substring];
len = tempRange.length;
loc = tempRange.location;
for (int i = 0; i != occurence; i++) {
NSUInteger endOfWord = len+loc;
trimmedString = [self stringByTrimmingString:trimmedString fromChar:endOfWord];
oldLength += [[self stringByTrimmingString:trimmedString toChar:endOfWord] length];
NSRange tmp = [trimmedString rangeOfString:substring];
len = tmp.length;
loc = tmp.location + oldLength;
}
NSRange returnRange = NSMakeRange(loc, len);
return returnRange;
}
Instead of trimming the string a bunch of times (slow), just use rangeOfString:options:range:, which searches only within the range passed as its third argument. See Apple's documentation.
So try:
- (NSRange)rangeOfString:(NSString *)substring
inString:(NSString *)string
atOccurence:(int)occurence
{
int currentOccurence = 0;
NSRange rangeToSearchWithin = NSMakeRange(0, string.length);
while (YES)
{
currentOccurence++;
NSRange searchResult = [string rangeOfString: substring
options: NULL
range: rangeToSearchWithin];
if (searchResult.location == NSNotFound)
{
return searchResult;
}
if (currentOccurence == occurence)
{
return searchResult;
}
int newLocationToStartAt = searchResult.location + searchResult.length;
rangeToSearchWithin = NSMakeRange(newLocationToStartAt, string.length - newLocationToStartAt);
}
}
You need to rework the whole code. While it may seem to work, it's poor coding and plain wrong, like permanently reassigning the same variable, initializing but reassigning one line later, releasing after returning (which will never work).
For your question: Just use rangeOfString:options:range:, and do this the appropriate number of times while just incrementing the starting point.

NSString character position

NSString *url = #"http://stackoverflow.com/questions/ask";
How can I get the character position of the 4th "/" ?
If you're just trying to get the last part of the url, you should be able to use this:
NSArray* items = [url componentsSeparatedByString:#"/"];
To get the index of the last '/' character:
NSRange range = [url rangeOfString:#"/" options:NSBackwardsSearch];
get the index value from range.location
To find the index of the fourth '/' character from the url:
int count = 0;
int index = -1;
for (unsigned int i=0; i < [url length]; ++i) {
if ([url characterAtIndex:i] == '/') {
++count;
if (count == 4) {
index = i;
break;
}
}
}
Usually you don't have to get the index of the letter /. You can just use many convenience methods defined in NSURL, see this Apple reference. I would do
NSURL* url=[NSURL URLWithString:#"http://stackoverflow.com/questions/ask"];
NSString* last=[url lastPathComponent]; // last is now #"ask"
another way you can use
[url rangeOfString:#"/" options:NSBackwardsSearch].location
hope it help!
I editted my answer after understanding your problem.
The answer of Hitesh it almost correct, you just need to do a little bit more
NSArray* items = [url componentsSeparatedByString:#"/"];
if ([items count] > 4) {
NSString *string = [items objectAtIndex:4];
}