In objective-c (for ios) I want to achieve the same as I can in AS3:
var test:String = "Abba";
var reg:RegExp = /(a)|(b)/g;
var replacement:Function = function (...args):String
{
var $1:String = args[1];//matched 'a'
var $2:String = args[2];//matched 'b'
if($1)
{
//replace a with -
return "-";
}
if ($2)
{
//replace b with +
return "+";
}
return null;
}
var result:String = test.replace(reg, replacement);//A++-
trace(test, result);//Abba A++-
In other words I would like to have ability to identify which capturing group was matched and replace it accordingly, I'm looking for examples on enumerateMatchesInString: but can't find anything that can solve my problem.
enumerateMatchesInString: calls a block with an NSTextCheckingResult for each match,
and rangeAtIndex:idx gives the range of a captured subgroup:
NSString *string = #"Abba";
NSString *pattern = #"(a)|(b)";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern
options:0
error:NULL];
NSMutableString *newString = [string mutableCopy];
[regex enumerateMatchesInString:string options:0 range:NSMakeRange(0, [string length])
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
NSRange r1 = [result rangeAtIndex:1];
if (r1.location != NSNotFound) {
[newString replaceCharactersInRange:r1 withString:#"-"];
}
NSRange r2 = [result rangeAtIndex:2];
if (r2.location != NSNotFound) {
[newString replaceCharactersInRange:r2 withString:#"+"];
}
}];
NSLog(#"%#", newString);
// Output: A++-
If the replacement strings have not the same length as the original strings, then it
gets slightly more complicated, because you have to keep track of the length changes
in the resulting string:
NSMutableString *newString = [string mutableCopy];
__block int offset = 0;
[regex enumerateMatchesInString:string options:0 range:NSMakeRange(0, [string length])
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
NSRange r1 = [result rangeAtIndex:1];
if (r1.location != NSNotFound) {
r1.location += offset;
NSString *repl = #"---";
[newString replaceCharactersInRange:r1 withString:repl];
offset += [repl length] - r1.length;
}
NSRange r2 = [result rangeAtIndex:2];
if (r2.location != NSNotFound) {
r2.location += offset;
NSString *repl = #"++";
[newString replaceCharactersInRange:r2 withString:repl];
offset += [repl length] - r2.length;
}
}];
NSLog(#"%#", newString);
// Output: A++++---
Related
I wonder how could I able to find all the numbers as follows.
Input
NSString* input = # "1m3s"
The desired output
#[#"1" #"3"]
I have tried the following approach
NSArray *arr = [input componentsSeparatedByCharactersInSet:
[NSCharacterSet characterSetWithCharactersInString:#"ms"]];
it returned me
#[#"1",#"3",#"#"]
Is there a better approach to solve this problem, any suggestion?
Even though this question has been marked as a duplication, I have tested the following answer but did not work.
Update
That could be any string value.
if input is #"11m32s" or #11m32 and then desired output would be #[#"11", #"32"];
if input is #"11x32" or #11x32y and then desired output would be #[#"11", #"32"];
Using a NSScanner would allow you to scan floats as well. In addition your array is populated directly with NSNumber instead of NSString.
NSString * input = # "12m32s";
NSScanner * aScanner = [NSScanner scannerWithString:input];
NSInteger aInt;
NSMutableArray * result = [NSMutableArray array];
while (!aScanner.isAtEnd)
{
if ([aScanner scanInteger:&aInt])
{
[result addObject:#(aInt)];
}
if (!aScanner.isAtEnd)
{
aScanner.scanLocation += 1;
}
}
NSLog(#"%#",result);
Try:
NSString* input = # "1m3s";
NSCharacterSet *nonDigitCharacterSet = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
NSArray *outArray = [input componentsSeparatedByCharactersInSet:nonDigitCharacterSet];
outArray = [outArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"length > 0"]];
To extract numbers you can use Regular Expression.
NSString* input = # "1m3s";
NSString *pattern = #"\\d+"; // searches for one or more digits
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:nil];
NSArray *matches = [regex matchesInString:input options:0 range:NSMakeRange(0, input.length)];
NSMutableArray *result = [[NSMutableArray alloc] init];
for (NSTextCheckingResult *match in matches) {
[result addObject: [input substringWithRange:match.range]];
}
NSLog(#"%#", result);
Or if you want to be more specific and extract the numbers in an expression ##m##s use
NSString* input = # "1m3s";
NSString *pattern = #"(\\d+)m(\\d+)s";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:nil];
NSTextCheckingResult *match = [regex firstMatchInString:input options:0 range:NSMakeRange(0, input.length)];
if (match) {
NSArray *result = #[[input substringWithRange:[match rangeAtIndex:1]], [input substringWithRange:[match rangeAtIndex:2]]];
NSLog(#"%#", result);
}
I think's it's helpful for you below the code work for me.
NSString *originalString = #"1m3s";
NSMutableArray *arr = [[NSMutableArray alloc] init];
for (int i=0; i<[originalString length]; i++) {
if (isdigit([originalString characterAtIndex:i])) {
NSMutableString *strippedString = [NSMutableString stringWithCapacity:10];
[strippedString appendFormat:#"%c",[originalString characterAtIndex:i]];
[arr addObject:strippedString];
}
}
NSLog(#"%#",arr.description);
Use below code :
NSCharacterSet *nonDigitCharacterSet = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
NSArray *outArray = [[input componentsSeparatedByCharactersInSet:nonDigitCharacterSet] componentsJoinedByString:#""];
Use this handy approach:
+ (NSArray *)extractNumberFromText:(NSString *)text
{
NSCharacterSet *nonDigitCharacterSet = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
NSMutableArray *numberArray = [[text componentsSeparatedByCharactersInSet:nonDigitCharacterSet]mutableCopy];
[numberArray removeObject:#""];
return numberArray;
}
Here is code to get your desire output:
NSString* input = #"1m3s";
NSString *newString = [[input componentsSeparatedByCharactersInSet:
[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]
componentsJoinedByString:#""];
NSMutableArray *array = [NSMutableArray array];
for (int i = 0; i < [newString length]; i++) {
NSString *ch = [newString substringWithRange:NSMakeRange(i, 1)];
[array addObject:ch];
}
NSLog(#"%#",array.description);
You can also use this code bellow.
NSString * String = #"24fsd35rf";
NSArray* Array = [String componentsSeparatedByCharactersInSet:
[[NSCharacterSet decimalDigitCharacterSet] invertedSet]];
NSLog(#"%#",[Array filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"self <> ''"]]);
I am using STTweet label for display atTag mentions. My problem is want to mention last name along with mention. How can i do that?
Below post my code
__block CommentsTableViewCell *hashtag=self;
labelCommenter_Comment.detectionBlock = ^(STTweetHotWord hotWord, NSString *string, NSString *protocol, NSRange range)
{
if ([string hasPrefix:#"#"] && [string length] > 1)
{
string = [string substringFromIndex:1];
[hashtag hashTagDelegateCalling:string];
}
else if ([string hasPrefix:#"#"] && [string length] > 1)
{
string = [string substringFromIndex:1];
NSMutableString *atString = [NSMutableString stringWithFormat:#"%#",string];
[arrayExp enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop)
{
if ([[obj valueForKey:#"userName"] isEqualToString:atString]) {
NSString *hashLinkValue = [obj valueForKey:#"hashLink"];
[hashtag atTheRateDelegateCalling:hashLinkValue];
}
}];
}
};
I am attempting to retrieve image url strings from some text, and then create an array containing all of these image url strings. I think I know how to get the image urls using NSRegularExpression, but I just don't know how to grab each individual result. I'm done find and replace before, but that just involves manipulating one giant string. Here is my code:
-(NSArray*)parseImages:(NSString*)contents {
NSArray* imageArray = [[NSArray alloc] init];
NSError* error = nil;
NSString* imageHandler = #"\(\?:\\<a\\shref=\"\)https\?:\/\/[\^\/\\s]\+\/\\S\+\\\.\(jpg|png|gif\)";
NSRegularExpression *imageGrabber = [NSRegularExpression regularExpressionWithPattern:imageHandler options:NSRegularExpressionCaseInsensitive error:&error];
if (error)
{
NSLog(#"Couldn't create regex with given string and options");
return nil;
} else {
//Code to add each individual match to imageArray
return imageArray;
}
Here's what I use for multiple matches in a regular expression:
NSArray *matchesArray = [self rangesOfString:#"{regex}" inString:aString];
for (NSValue *rangeVal in matchesArray)
{
NSRange range = [rangeVal rangeValue];
if (range.location != NSNotFound) {
// do stuff with the found range - like add to an NSMutableArray!
}
}
And the rangesOfString method:
- (NSArray *)rangesOfString:(NSString *)searchString inString:(NSString *)str {
NSMutableArray *results = [NSMutableArray array];
NSRange searchRange = NSMakeRange(0, [str length]);
NSRange range;
while ((range = [str rangeOfString:searchString options:NSRegularExpressionSearch|NSCaseInsensitiveSearch range:searchRange]).location != NSNotFound) {
[results addObject:[NSValue valueWithRange:range]];
searchRange = NSMakeRange(NSMaxRange(range), [str length] - NSMaxRange(range));
}
return results;
}
Let Apple do the heavy-lifting with NSDataDetector
NSString *text = #"jibberish http://link1.com jibberish http://link2.com jibberish";
NSError *error;
NSDataDetector *dd = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:&error];
NSArray *matches = [dd matchesInString:text options:0 range:NSMakeRange(0, text.length)];
NSMutableArray *links = [NSMutableArray new];
for (NSTextCheckingResult *result in matches) {
[links addObject:[result URL]];
}
NSLog(#"links: %#", links);
NSLog output:
links: (
"http://link1.com",
"http://link2.com"
)
If there is a need to restrict to extension types:
Add the extensions to a set:
NSSet *extensions = [NSSet setWithArray: #[#"jpg", #"png", #"gif"]];
Add only to the array only if the extension is in the set:
NSString *ext = [[url resourceSpecifier] pathExtension];
if ([extensions containsObject:ext]) {
[links addObject:url];
}
I have an NSString for example "This is my question".I want to find all the indices of the character/substring "i" ie In this case If index starts from 0,then I want 2,5,16 as my answer.
The other answer is a bit of an overkill. Why don't you simply iterate over the characters like this:
NSString *x = #"This is my question";
for (NSUInteger i=0;i<[x length];i++)
{
if ([x characterAtIndex:i]=='i')
{
NSLog(#"found: %d", i);
}
}
It outputs exactly your positions:
found: 2
found: 5
found: 16
I'd like suggest my solution. It is like this:
NSString* str = #"This is my question";
NSArray* arr = [str componentsSeparatedByString: #"i"];
NSMutableArray* marr = [NSMutableArray arr];
NSInteger cnt = 0;
for (NSInteger i = 0; i < ([arr count]); i++)
{
NSString* s = [arr objectAtIndex: i];
cnt += [s length];
[marr addObject: [NSNumber numberWithInt: cnt]];
cnt += [#"i" length];
}
NSLog(#"%#", [marr description]);
On console:
2
5
16
I don't know is there any built-in functions available for doing this. You can use this method:
- (NSMutableArray *)indexOfCharacter:(char)c inString:(NSString*)string
{
NSMutableArray *returnArray = [[NSMutableArray alloc] init];
for(int i=0;i<string.length;i++)
{
if(c == [string characterAtIndex:i])
{
[returnArray addObject:[NSNumber numberWithInt:i]];
}
}
return returnArray;
}
Using NSRange and loop and with some string manipulation you can easily do it.
NSString *string = #"This is my question";
NSString *substring = #"i";
NSRange searchRange = NSMakeRange(0,string.length);
NSRange foundRange;
while (searchRange.location < string.length)
{
searchRange.length = string.length-searchRange.location;
foundRange = [string rangeOfString:substring options:nil range:searchRange];
if (foundRange.location != NSNotFound)
{
// found an occurrence of the char
searchRange.location = foundRange.location+foundRange.length;
NSLog(#"Location of '%#' is %d",substring,searchRange.location-1);
}
}
EDIT
Using NSRegularExpression and NSRange you can do like this.
NSString *string = #"This is my question";
NSString *substring = #"i";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:substring
options:0
error:NULL];
[regex enumerateMatchesInString:string options:0 range:NSMakeRange(0, [string length])
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
NSRange range = [result range];
NSLog(#"Location of '%#' is %d",substring, range.location);
}];
output is
Location of 'i' is 2
Location of 'i' is 5
Location of 'i' is 16
This is my attempt at a no loop code of getting what you want. I coded this blind, meaning not-tested etc. Its basically a recursive function, but I think it gets you the general idea.
- (NSArray *)getAllEyes:(NSString *)s index:(int)index) {
if (!s || s.length <= 0 || index >= s.length) return [NSArray new];
NSRange *r = [s rangeOfString(#"i") options:NSLiteralSearch range:NSMakeRange(index, s.length - index)];
if (r.location == NSNotFound) {
return [NSArray new];
} else {
NSMutableArray *array = [NSMutableArray new];
[array addObject:#(r.location)];
[array addObjectsFromArray:[self getAllEyes:s index:r.location + 1]];
return array;
}
}
// usage:
NSArray *allEyes = [self getAllEyes:#""];
for (NSNumber *n in allEyes) {
NSLog(#"i = %#", n);
}
I have two NSStrings: orgText and searchLetter.
I want to highlight every occurrences of the searchLetter in the orgText with a red color.
How can I get the NSRange of all occurrences of the searchLetter ?
for eg :
suppose: orgText = "abcahaiapaoiuiapplma"
searchLetter = "a".
I want to hightlight all "a" occurrences in "abcahaiapaoiuiapplma" with red color.
Thanks.
I wrote this method for my project - SUITextView with highlight:
- (NSMutableAttributedString*) setColor:(UIColor*)color word:(NSString*)word inText:(NSMutableAttributedString*)mutableAttributedString {
NSUInteger count = 0, length = [mutableAttributedString length];
NSRange range = NSMakeRange(0, length);
while(range.location != NSNotFound)
{
range = [[mutableAttributedString string] rangeOfString:word options:0 range:range];
if(range.location != NSNotFound) {
[mutableAttributedString setTextColor:color range:NSMakeRange(range.location, [word length])];
range = NSMakeRange(range.location + range.length, length - (range.location + range.length));
count++;
}
}
return mutableAttributedString;
}
And in my category of NSMutableAttributedString:
- (void) setTextColor:(UIColor*)color range:(NSRange)range {
// kCTForegroundColorAttributeName
[self removeAttribute:(NSString*)kCTForegroundColorAttributeName range:range]; // Work around for Apple leak
[self addAttribute:(NSString*)kCTForegroundColorAttributeName value:(id)color.CGColor range:range];
}
I'm not seeing any solution with regular expression, so I've created an elegant one, it may be useful for someone in the future.
- (BOOL)highlightString:(NSString *)string inText:(NSMutableAttributedString *)attributedString withColour:(UIColor *)color {
NSError *_error;
NSRegularExpression *_regexp = [NSRegularExpression regularExpressionWithPattern:string options:NSRegularExpressionCaseInsensitive error:&_error];
if (_error == nil) {
[_regexp enumerateMatchesInString:attributedString.string options:NSMatchingReportProgress range:NSMakeRange(0, attributedString.string.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
if (result.numberOfRanges > 0) {
for (int i = 0; i < result.numberOfRanges; i++) {
[attributedString addAttribute:NSBackgroundColorAttributeName value:color range:[result rangeAtIndex:i]];
}
}
}];
return TRUE;
} else {
return FALSE;
}
}
Code crash at "setTextColor" for MutableAttributeString
instead of it use below code
NSDictionary *tempdict=[NSDictionary dictionaryWithObjectsAndKeys:[UIFont boldSystemFontOfSize:12.0],NSFontAttributeName,color,NSForegroundColorAttributeName, nil];
[mutableAttributedString setAttributes:tempdict range:NSMakeRange(range.location, [word length])];
this is an easier way of doing it
NSString *str = #"hello world";
NSMutableAttributedString *attr = [[NSMutableAttributedString alloc] initWithString:str];
[attr addAttributes:#{NSForegroundColorAttributeName : [UIColor redColor]}
range:[str rangeOfString:#"world"]];