How to get NSRange(s) for a substring in NSString? [duplicate] - ios

This question already has answers here:
How to get all NSRange of a particular character in a NSString?
(4 answers)
Closed 9 years ago.
NSString *str = #" My name is Mike, I live in California and I work in Texas. Weather in California is nice but in Texas is too hot...";
How can I loop through this NSString and get NSRange for each occurrence of "California", I want the NSRange because I would like to change it's color in the NSAttributed string.
NSRange range = NSMakeRange(0, _stringLength);
while(range.location != NSNotFound)
{
range = [[attString string] rangeOfString: #"California" options:0 range:range];
if(range.location != NSNotFound)
{
range = NSMakeRange(range.location + range.length, _stringLength - (range.location + range.length));
[attString addAttribute:NSForegroundColorAttributeName value:_green range:range];
}
}

Lots of ways of solving this problem - NSScanner was mentioned; rangeOfString:options:range etc. For completeness' sake, I'll mention NSRegularExpression. This also works:
NSMutableAttributedString *mutableString = nil;
NSString *sampleText = #"I live in California, blah blah blah California.";
mutableString = [[NSMutableAttributedString alloc] initWithString:sampleText];
NSString *pattern = #"(California)";
NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:nil];
// enumerate matches
NSRange range = NSMakeRange(0,[sampleText length]);
[expression enumerateMatchesInString:sampleText options:0 range:range usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
NSRange californiaRange = [result rangeAtIndex:0];
[mutableString addAttribute:NSForegroundColorAttributeName value:[NSColor greenColor] range:californiaRange];
}];

with
[str rangeOfString:#"California"]
and
[str rangeOfString:#"California" options:YOUR_OPTIONS range:rangeToSearch]

You may use rangeOfString:options:range: or NSScanner (there are other possibilities like regexps but anyway). It's easier to use first approach updating range, i.e. search for first occurrence and then depending on the result update the search range. When the search range is empty, you've found everything;

Related

Regex for finding occurrences of all strings present in the original searched term

I'm searching for string "longer" on string: "This is a long sentence. But can be longer."
I am trying to get the range of all the words that are present in the original search term. In the above scenario, it would be the ranges of "long" and "longer". Please let me know if this is possible with regex?
The code that I'm using:
NSMutableArray *arrayOfAllRanges = [[NSMutableArray alloc] init];
NSString *completeString = #"This is a long sentence. But can be longer.";
NSString *searchedTerm = #"longer";
NSRange range = NSMakeRange(0, completeString.length);
NSString *pattern = [NSString stringWithFormat:#"(%#)", searchedTerm];
NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:nil];
[expression enumerateMatchesInString:completeString options:0 range:range usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop)
{
NSRange foundRange = [result rangeAtIndex:0];
[arrayOfAllRanges addObject:[NSValue valueWithRange:foundRange]];
}];
NSLog(#"Array of all ranges %#", arrayOfAllRanges);
The above code returns just the occurrences of "longer" with the regex "(longer)" but I'm looking for a replacement regex that finds the text "long" as well.

Remove "?" from NSString IOS

I am trying to remove all symbols from a string, it works fine with below code for all symbols except "?".
NSString *newString = self.titleString;
NSArray *characters = #[#"<", #"!", #"#", #"#", #"$", #"%", #"^", #"&", #"*", #"(", #")", #",", #"_", #"+", #"|", #">", #"?", #" "];
for (NSString *str in characters) {
newString = [newString stringByReplacingOccurrencesOfString:str withString:#""];
}
You can use stringByReplacingOccurrencesOfString with the regular expression option, NSRegularExpressionSearch:
NSString *output = [input stringByReplacingOccurrencesOfString:#"[<>!##$%^&*(),_+?| ]" withString:#"" options:NSRegularExpressionSearch range:NSMakeRange(0, [input length])];
You can also take advantage of other regular expression features, e.g. replace all non-letter characters:
NSString *output = [input stringByReplacingOccurrencesOfString:#"\\P{L}" withString:#"" options:NSRegularExpressionSearch range:NSMakeRange(0, [input length])];
or not A-Z:
NSString *output = [input stringByReplacingOccurrencesOfString:#"[^a-zA-Z]" withString:#"" options:NSRegularExpressionSearch range:NSMakeRange(0, [input length])];
It just depends upon precisely what you're trying to achieve.
You can remove all characters in a single call using NSRegularExpression:
NSString *string = self.titleString;
NSError *error = nil;
// Prepare the regular expression that matches any of your characters
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"[<>!##$%^&*(),_+?| ]"
options:NSRegularExpressionCaseInsensitive
error:&error];
// Replace all matches with an empty string
string = [regex stringByReplacingMatchesInString:string options:0 range:NSMakeRange(0, [string length]) withTemplate:#""];
You have to escape the ? like that: "\?". Otherwise it won't work properly. ? only means in regex stands for 0 or 1 occurences and so you have to say to objective-c that it is a real char you want to test.
If this is for editing user text you might want to consider using a union of more than one NSCharacterSet - this will help it be more language-friendly when you localize/internationalize your app.
NSString *myInputText = #"asd;jkfhals#$%^%$&1asldiguhd";
NSCharacterSet *nonAlphanumeric = [[NSMutableCharacterSet alphanumericCharacterSet] invert];
NSArray *parts = [myInputText componentsSeparatedByCharactersInSet:nonAlphanumeric];
NSArray *mySafeOutputText = [parts componentsJoinedByString:#""];
It's a little non-intuitive to use the components method, but unfortunately Apple doesn't provide a stringByReplacingCharactersInSet: method. :(

Detect underscore from a particular word of a UITextView's text

I want to detect "_" from a particular word of a UITextView's text.
I already tried this :
But this calculates the range of first underscore only.
NSMutableAttributedString *string = [[NSMutableAttributedString alloc]initWithString:textView.text];
NSRange range=[textView.text rangeOfString:#"_"];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor clearColor] range:range];
textView.attributedText=string;
My output is coming like this
Tadeusz_Kościuszko was a military leader who became a national hero in
Poland. A poster for the Paris premiere of Jules_Massenet's 1910 opera
Don_Quichotte.
And I want something like this:
Tadeusz Kościuszko was a military leader who became a national hero in
Poland. A poster for the Paris premiere of Jules Massenet's 1910 opera
Don Quichotte.
Also I want to clear color the underscores just from the names. Not from the other text of UITextView.
I dont want to remove it from the whole text of UITextView but just from the particular words.
Anyone having suggestions?
Thanks.
textView.text = [textView.text stringByReplacingOccurrencesOfString:#"_" withString:#" "];
NSMutableAttributedString *string = [[NSMutableAttributedString alloc]initWithString:textView.text];
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"(_)" options:kNilOptions error:nil];
NSRange range = NSMakeRange(0,string.length);
[regex enumerateMatchesInString:string options:kNilOptions range:range usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
NSRange subStringRange = [result rangeAtIndex:1];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:subStringRange];
}];
textView.attributedText=string;
try this -
NSString *str = #"Tadeusz_Kościuszko was a military leader who became a national hero in Poland. A poster for the Paris premiere of Jules_Massenet's 1910 opera Don_Quichotte.";
NSString *newStr = [str stringByReplacingOccurrencesOfString:#"_" withString:#" "];
NSLog(#"NEW STR ::::: %#",newStr);
NSString *str = #"This_is_a_string";
str = [str stringByReplacingOccurrencesOfString:#"_"
withString:#" "];
// str = "This is a string"
More on NSString
Found the workaround :)
NSString *strTemp = textView.text;
NSMutableAttributedString *mutString = [[NSMutableAttributedString alloc]initWithString:strTemp];
NSString *substring = #"_";
NSRange searchRange = NSMakeRange(0,mutString.length);
NSRange wholeTextRange = [strTemp rangeOfString:strTemp];
[mutString addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:wholeTextRange];
NSRange foundRange;
while (searchRange.location < mutString.length)
{
searchRange.length = mutString.length-searchRange.location;
foundRange = [strTemp rangeOfString:substring options:nil range:searchRange];
if (foundRange.location != NSNotFound) {
// found an occurrence of the substring! do stuff here
[mutString addAttribute:NSForegroundColorAttributeName value:[UIColor clearColor] range:foundRange];
searchRange.location = foundRange.location+foundRange.length;
} else {
// no more substring to find
[txtComment setAttributedText:mutString];
break;
}
}
If you want to selectively remove underscores you need to know the range of text from which you want to remove them.
Then you can use a regular expression to get an array of ranges which match the underscore in that known range.
NSError *error;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"_" options:0 error:&error];
NSArray *matchingRangesInSelectedRange = [regex matchesInString:yourString options:0 range:knownRangeToCheckForMatches];
You can then iterate over the ranges in the array and do whatever changes you wish.
If you know which strings should not be cleaned or which that should not be cleaned you could do something like this:
NSString *stringWithUnderScore = #"A rather long text with some_odd_underscores but also names like André_Franquin & Albert_Uderzo";
NSSet *stringsThatShouldKeepUnderscore = [NSSet setWithObjects:#"some_odd_underscores", nil];
NSArray *singleStrings = [stringWithUnderScore componentsSeparatedByString:#" "];
NSMutableString *newCompleteString = [[NSMutableString alloc] init];
for (NSString *singleString in singleStrings) {
if (![stringsThatShouldKeepUnderscore containsObject:singleString]){
NSString *fixedString = [singleString stringByReplacingOccurrencesOfString:#"_" withString:#" "];
[newCompleteString appendString: fixedString];
} else{
[newCompleteString appendString:singleString];
}
[newCompleteString appendString:#" "];
}
NSLog(#"new string:%#",newCompleteString);
Edit: If you do not have this information you could try to make some kind of parser checking if each of the strings separated by "_" have capital-letters, indicating a name. Not fail-safe, but without knowledge about the text I can't really see any better option.

Getting subString from string ios?

I have a following string in iOS :-
[{"status":"0","eventid":"126"}]15.511563,73.809732[{"status":"0"}]
And I am trying to fetch this :-
[{"status":"0","eventid":"126"}]
i.e. the entire portion of string before first ] closing bracket.
I tried this in which I get a substring of 31 characters, but this won't work if the contents between the brackets changes.
NSRange start = [result1 rangeOfString:#"["];
NSString *shortString =[result1 substringWithRange:NSMakeRange(start.location, 31)];
result1 = [result1 substringToIndex:shortString.length];
NSLog(#"Response- %#",result1);
What is the correct approach?
Just like you are getting the start range (NSRange start = [result1 rangeOfString:#"["];), also get the end range:
NSRange end = [result1 rangeOfString:#"]"];
Now you have enough information to extract the substring:
NSString *result = [result1 substringWithRange:NSMakeRange(start.location, end.location - start.location)];
In your current code, you don't need to use substring... methods twice as you have already extracted the string you want in the first call. Making the second call is just ignoring the bit of code which found the start location and assuming that you always want the substring from the start of the string, which is less flexible.
Make the END Range also
NSRange start;
NSRange end;
start = [result1 rangeOfString: #"["];
end = [result1 rangeOfString: #"]"];
NSString *newResult = [result1 substringWithRange:NSMakeRange(start.location+1, end.location)];
NSLog(#"%#", newResult);
You could try using a NSRegularExpression:
NSError *error = NULL;
NSRegularExpression *regex =
[NSRegularExpression regularExpressionWithPattern:#"\\[(.*?)\\]"
options:NSRegularExpressionCaseInsensitive
error:&error];
Now, search for the first match:
NSString *string = #"[{\"status\":\"0\",\"eventid\":\"126\"}]15.511563,73.809732[{\"status\":\"0\"}]";
NSTextCheckingResult *match =
[regex firstMatchInString:string
options:0
range:NSMakeRange(0, [string length])];
Now you can get the range for the capture group:
NSRange block = [match rangeAtIndex:1];

Finding first letter in NSString and counting backwards

I'm new to IOS, and was looking for some guidance.
I have a long NSString that I'm parsing out. The beginning may have a few characters of garbage (can be any non-letter character) then 11 digits or spaces, then a single letter (A-Z). I need to get the location of the letter, and get the substring that is 11 characters behind the letter to 1 character behind the letter.
Can anyone give me some guidance on how to do that?
Example: '!!2553072 C'
and I want : '53072 '
You can accomplish this with the regex pattern: (.{11})\b[A-Z]\b
The (.{11}) will grab any 11 characters and the \b[A-Z]\b will look for a single character on a word boundary, meaning it will be surrounded by spaces or at the end of the string. If characters can follow the C in your example then remove the last \b. This can be accomplished in Objective-C like so:
NSError *error;
NSString *example = #"!!2553072 C";
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:#"(.{11})\\b[A-Z]\\b"
options:NSRegularExpressionCaseInsensitive
error:&error];
if(!regex)
{
//handle error
}
NSTextCheckingResult *match = [regex firstMatchInString:example
options:0
range:NSMakeRange(0, [example length])];
if(match)
{
NSLog(#"match: %#", [example substringWithRange:[match rangeAtIndex:1]]);
}
There may be a more elegant way to do this involving regular expressions or some Objective-C wizardry, but here's a straightforward solution (personally tested).
-(NSString *)getStringContent:(NSString *)input
{
NSString *substr = nil;
NSRange singleLetter = [input rangeOfCharacterFromSet:[NSCharacterSet letterCharacterSet]];
if(singleLetter.location != NSNotFound)
{
NSInteger startIndex = singleLetter.location - 11;
NSRange substringRange = NSMakeRange(start, 11);
substr = [tester substringWithRange:substringRange];
}
return substr;
}
You can use NSCharacterSets to split up the string, then take the first remaining component (consisting of your garbage and digits) and get a substring of that. For example (not compiled, not tested):
- (NSString *)parseString:(NSString *)myString {
NSCharacterSet *letters = [NSCharacterSet letterCharacterSet];
NSArray *components = [myString componentsSeparatedByCharactersInSet:letters];
assert(components.count > 0);
NSString *prefix = components[0]; // assuming relatively new Xcode
return [prefix substringFromIndex:(prefix.length - 11)];
}
//to get rid of all non-Digits in a NSString
NSString *customerphone = CustomerPhone.text;
int phonelength = [customerphone length];
NSRange customersearchRange = NSMakeRange(0, phonelength);
for (int i =0; i < phonelength;i++)
{
const unichar c = [customerphone characterAtIndex:i];
NSString* onechar = [NSString stringWithCharacters:&c length:1];
if(!isdigit(c))
{
customerphone = [customerphone stringByReplacingOccurrencesOfString:onechar withString:#"*" options:0 range:customersearchRange];
}
}
NSString *PhoneAllNumbers = [customerphone stringByReplacingOccurrencesOfString:#"*" withString:#"" options:0 range:customersearchRange];

Resources