Match NSArray of characters Objective-C - iphone

I have to match the number of occurrences of n special characters in a string.
I thought to create an array with all these chars (they are 20+) and create a function to match each of them.
I just have the total amount of special characters in the string, so I can make some math count on them.
So in the example:
NSString *myString = #"My string #full# of speci#l ch#rs & symbols";
NSArray *myArray = [NSArray arrayWithObjects:#"#",#"#",#"&",nil];
The function should return 5.
Would it be easier match the characters that are not in the array, take the string length and output the difference between the original string and the one without special chars?
Is this the best solution?

NSString *myString = #"My string #full# of speci#l ch#rs & symbols";
//even in first continuous special letters it contains -it will return 8
//NSString *myString = #"#&#My string #full# of speci#l ch#rs & symbols";
NSArray *arr=[myString componentsSeparatedByCharactersInSet:[NSMutableCharacterSet characterSetWithCharactersInString:#"##&"]];
NSLog(#"resulted string : %# \n\n",arr);
NSLog(#"count of special characters : %i \n\n",[arr count]-1);
OUTPUT:
resulted string : (
"My string ",
full,
" of speci",
"l ch",
"rs ",
" symbols"
)
count of special characters : 5

You should utilize an NSRegularExpression, its perfect for your scenario. You can create one like this:
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"(#|&)" options:NSRegularExpressionCaseInsensitive error:&error];
NSUInteger numberOfMatches = [regex numberOfMatchesInString:string options:0 range:NSMakeRange(0, [string length])];
Caveat: I ripped the code from the Apple Developer site. And I'm no regex guru so you will have to tweak the pattern. But you get the gist.

You should look also at NSRegularExpression:
- (NSUInteger)numberOfCharacters:(NSArray *)arr inString:(NSString *)str {
NSMutableString *mutStr = #"(";
for(i = 0; i < [arr count]; i++) {
[mutStr appendString:[arr objectAtIndex:i]];
if(i+1 < [arr count]) [mutStr appendString:#"|"];
}
[mutStr appendString:#")"];
NSRegularExpression *regEx = [NSRegularExpression regularExpressionWithPattern:mutStr options:NSRegularExpressionCaseInsensitive error:nil];
NSUInteger *occur = [regExnumberOfMatchesInString:str options:0 range:NSMakeRange(0, [string length])];
[mutStr release];
return occur;
}
Usage example:
NSString *myString = #"My string #full# of speci#l ch#rs & symbols";
NSArray *myArray = [NSArray arrayWithObjects:#"#",#"#",#"&",nil];
NSLog(#"%d",[self numberOfCharacters:myArray inString:myString]); // will print 5

Related

regex to find hashtags in tweet not working correctly

I am trying to build a function to find a hashtags in tweest. And surround them with an HTML <a> tag. so that I can link to them. Here is what I do.
NSError* error = nil;
NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:#"(?:\\s|\\A)[##]+([A-Za-z0-9-_]+)" options:0 error:&error];
NSArray* matches = [regex matchesInString:tweetText options:0 range:NSMakeRange(0, [tweetText length])];
for ( NSTextCheckingResult* match in matches )
{
NSString* matchText = [tweetText substringWithRange:[match range]];
NSString *matchText2 = [matchText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSString *search = [matchText2 stringByReplacingOccurrencesOfString:#"#"
withString:#""];
NSString *searchHTML= [NSString stringWithFormat:#"<a href='https://twitter.com/search?q=%%23%#'>%#</a>",search,matchText];
tweetText = [tweetText stringByReplacingOccurrencesOfString:matchText
withString:searchHTML];
NSLog(#"match: %#", tweetText);
}
Before I execute this function, the tweetText is looped through another function to find the URL. so the tweet can contain the following. <a href='http://google.be' target='_blank'>http://google.be</a>
Now sometimes it places another tag around other links and not only around the hashtags.
Can somebody help me with this.
TIP
I am trying to transform the following JAVA code into OBJ-C
String patternStr = "(?:\\s|\\A)[##]+([A-Za-z0-9-_]+)"
Pattern pattern = Pattern.compile(patternStr)
Matcher matcher = pattern.matcher(tweetText)
String result = "";
// Search for Hashtags
while (matcher.find()) {
result = matcher.group();
result = result.replace(" ", "");
String search = result.replace("#", "");
String searchHTML="<a href='http://search.twitter.com/search?q=" + search + "'>" + result + "</a>"
tweetText = tweetText.replace(result,searchHTML);
}
EDIT
Gers, we kijken er al naar uit! “#GersPardoel: We zitten in België straks naar Genk!!<a href='<a href<a href='https://twitter.com/search?q=%23='http'>='http</a>s://twitter.com/search?q=%23https:/'>https:/</a>/twitter.com/search?q=%23engaan'> #engaan</a>” #GOS12 #genk #fb
The problem is that you're modifying your tweetText variable (tweetText = ...) as you're looping through matches. Imagine what happens the next time code enters the loop? The substringWithRange will not work properly since it was created on the original string. Try to rectify the problem and if you're unable to do it, check the solution here: http://pastebin.com/DyQqtRzA
EDIT: Adding solution here:
NSError* error = nil;
NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:#"(?:\\s|\\A)[##]+([A-Za-z0-9-_]+)" options:0 error:&error];
NSArray* matches = [regex matchesInString:tweetText options:0 range:NSMakeRange(0, [tweetText length])];
NSString* processedString = [[tweetText copy] autorelease];
for ( NSTextCheckingResult* match in matches )
{
NSString* matchText = [tweetText substringWithRange:[match range]];
NSString *matchText2 = [matchText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSString *search = [matchText2 stringByReplacingOccurrencesOfString:#"#"
withString:#""];
NSString *searchHTML= [NSString stringWithFormat:#"<a href='https://twitter.com/search?q=%%23%#'>%#</a>",search,matchText];
processedString = [processedString stringByReplacingOccurrencesOfString:matchText
withString:searchHTML];
NSLog(#"match: %#", processedString);
}

parsing string starting with # and # in objective-C

So I am trying to parse a string that has the following format:
baz#marroon#red#blue #big#cat#dog
or, it can also be separated by spaces:
baz #marroon #red #blue #big #cat #dog
and here's how I am doing it now:
- (void) parseTagsInComment:(NSString *) comment
{
if ([comment length] > 0){
NSArray * stringArray = [comment componentsSeparatedByString:#" "];
for (NSString * word in stringArray){
}
}
}
I've got the components separated by space working, but what if it has no space.. how do I iterate through these words? I was thinking of using regex.. but I have no idea on how to write such regex in objective-C. Any idea, for a regex that would cover both of these cases?
Here's my first attempt:
NSError * error;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"(#|#)\\S+" options:NSRegularExpressionCaseInsensitive error:&error];
NSArray* wordArray = [regex matchesInString:comment
options:0 range:NSMakeRange(0, [comment length])];
for (NSString * word in wordArray){
}
Which doesn't work.. I think my regex is wrong.
Here is a way to do it using NSScanner that puts the separated strings and a string representation of their ranges into an array (this assumes that your original string started with a # -- if it doesn't and you need it to, then just prepend the hash to the string at the start).
NSMutableArray *array = [NSMutableArray array];
NSString *str = #"#baz#marroon#red#blue #big#cat#dog";
NSScanner *scanner = [NSScanner scannerWithString:str];
NSCharacterSet *searchSet = [NSCharacterSet characterSetWithCharactersInString:#"##"];
NSString *outputString;
while (![scanner isAtEnd]) {
[scanner scanUpToCharactersFromSet:searchSet intoString:nil];
[scanner scanCharactersFromSet:searchSet intoString:&outputString];
NSString *symbol = [outputString copy];
[scanner scanUpToCharactersFromSet:searchSet intoString:&outputString];
NSString *wholePiece = [[symbol stringByAppendingString:outputString]stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSString *rangeString = NSStringFromRange([str rangeOfString:wholePiece]);
[array addObject:wholePiece];
[array addObject:rangeString];
}
NSLog(#"%#",array);
I think the regular expression you really want is [##]?\\w+. It will find groups of letters optionally preceded by an # or #. Your expression wouldn't work because it looks for any non-space character, which includes # and #. (Depending on what can be in the "words," you might want something more or less specific than \w, but it isn't clear from the question.)
If you need the ranges, then NSRegularExpression probably works well:
NSString *comment = #"#baz#marroon#red#blue #big#cat#dog";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"[##]\\w+" options:0 error:nil];
NSArray* wordArray = [regex matchesInString:comment
options:0
range:NSMakeRange(0, [comment length])];
for (NSTextCheckingResult *result in wordArray)
NSLog(#"%#", [comment substringWithRange:result.range]);
Or, [##][a-zA-z]+ works if you're ok with ASCII alpha words only.

Take part of string in-between symbols?

I would like to be able to take the numbers lying behind the ` symbol and in front of any character that is non-numerical and convert it into a integer.
Ex.
Original String: 2*3*(123`)
Result: 123
Original String: 4`12
Result: 4
Thanks,
Regards.
You can use regular expressions. You can find all the occurrences like this:
NSString *mystring = #"123(12`)456+1093`";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"([0-9]+)`" options:0 error:nil];
NSArray *matches = [regex matchesInString:mystring options:0 range:NSMakeRange(0, mystring.length)];
for (NSTextCheckingResult *match in matches) {
NSLog(#"%#", [mystring substringWithRange:[match rangeAtIndex:1]]);
}
// 12 and 1093
If you only need one occurrence, then replace the for loop with the following:
if (matches.count>0) {
NSTextCheckingResult *match = [matches objectAtIndex:0];
NSLog(#"%#", [mystring substringWithRange:[match rangeAtIndex:1]]);
}
There can be better way to do this, Quickly i could come up with this,
NSString *mystring = #"123(12`)";
NSString *neededString = nil;
NSScanner *scanner =[NSScanner scannerWithString:mystring];
[scanner scanUpToString:#"`" intoString:&neededString];
neededString = [self reverseString:neededString];
NSLog(#"%#",[self reverseString:[NSString stringWithFormat:#"%d",[neededString intValue]]]);
To reverse a string you can see this

returning all index of a character in a NSString

IS there a method that would return all the index of the occurences of the letter 'a' in a NSString lets say? Tried looking at the documentation and there seems that there isn't any. So I might have to break the NSString to an NSArray of chars and iterate?
Try [NSRegularExpression enumerateMatchesInString:options:range:usingBlock:]. Or indeed, any of the other NSRegularExpression matching methods. They won't return an NSIndexSet - it'll be an array of NSTextChecking objects - but you can quite easily get the index out of that.
Here's some (untested!) sample code:
NSString* aString = #"Here's a string, that contains some letters a";
NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:#"a" options:0 error:NULL];
NSArray* matches = [regex matchesInString:aString options:0 range:NSMakeRange(0,[aString length])];
for(NSTextCheckingResult* i in matches) {
NSRange range = i.range;
NSUInteger index = range.location; //the index you were looking for!
//do something here
}
It's actually more efficient to use enumerateMatchesInString, but I don't know how familiar you are with Blocks, so I opted for the more common fast enumeration of an NSArray.
Update: the same code using Blocks.
NSString* aString = #"Here's a string, that contains some letters a";
NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:#"a";
[regex enumerateMatchesInString:aString
options:0
range:NSMakeRange(0,[aString length])
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
NSRange range = result.range;
NSUInteger index = range.location; //the index you were looking for
//do work here
}];
NSString *full_string=#"The Quick Brown Fox Brown";
NSMutableArray *countloc=[[NSMutableArray alloc]init];
int temp=0;
int len=[full_string length];
for(int i =0;i<[full_string length];i++)
{
NSRange range=[full_string rangeOfString:#"Brown" options:0 range:NSMakeRange(temp,len-1)];
if(range.location<[full_string length])
[countloc addObject:[NSString stringWithFormat:#"%d",range.location]];
temp=range.location+1;
len=[full_string length]-range.location;
i=temp;
}
Here searching for the substring Brown and
Location of the substring is stored in the array countloc

NSString to NSArray

I want to split an NSString into an NSArray. For example, given:
NSString *myString=#"ABCDEF";
I want an NSArray like:
NSArray *myArray={A,B,C,D,E,F};
How to do this with Objective-C and Cocoa?
NSMutableArray *letterArray = [NSMutableArray array];
NSString *letters = #"ABCDEF𝍱क्";
[letters enumerateSubstringsInRange:NSMakeRange(0, [letters length])
options:(NSStringEnumerationByComposedCharacterSequences)
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
[letterArray addObject:substring];
}];
for (NSString *i in letterArray){
NSLog(#"%#",i);
}
results in
A
B
C
D
E
F
𝍱
क्
enumerateSubstringsInRange:options:usingBlock: available for iOS 4+ can enumerate a string with different styles. One is called NSStringEnumerationByComposedCharacterSequences, what will enumerate letter by letter but is sensitive to surrogate pairs, base characters plus combining marks, Hangul jamo, and Indic consonant clusters, all referred as Composed Character
Note, that the accepted answer "swallows" 𝍱and breaks क् into क and ्.
Conversion
NSString * string = #"A B C D E F";
NSArray * array = [string componentsSeparatedByString:#" "];
//Notice that in this case I separated the objects by a space because that's the way they are separated in the string
Logging
NSLog(#"%#", array);
This is what the console returned
NSMutableArray *chars = [[NSMutableArray alloc] initWithCapacity:[theString length]];
for (int i=0; i < [theString length]; i++) {
NSString *ichar = [NSString stringWithFormat:#"%C", [theString characterAtIndex:i]];
[chars addObject:ichar];
}
This link contains examples to split a string into a array based on sub strings and also based on strings in a character set. I hope that post may help you.
here is the code snip
NSMutableArray *characters = [[NSMutableArray alloc] initWithCapacity:[myString length]];
for (int i=0; i < [myString length]; i++) {
NSString *ichar = [NSString stringWithFormat:#"%c", [myString characterAtIndex:i]];
[characters addObject:ichar];
}
Without loop you can use this:
NSString *myString = #"ABCDEF";
NSMutableString *tempStr =[[NSMutableString alloc] initWithString:myString];
if([myString length] != 0)
{
NSError *error = NULL;
// declare regular expression object
NSRegularExpression *regex =[NSRegularExpression regularExpressionWithPattern:#"(.)" options:NSMatchingReportCompletion error:&error];
// replace each match with matches character + <space> e.g. 'A' with 'A '
[regex replaceMatchesInString:tempStr options:NSMatchingReportCompletion range:NSMakeRange(0,[myString length]) withTemplate:#"$0 "];
// trim last <space> character
[tempStr replaceCharactersInRange:NSMakeRange([tempStr length] - 1, 1) withString:#""];
// split into array
NSArray * arr = [tempStr componentsSeparatedByString:#" "];
// print
NSLog(#"%#",arr);
}
This solution append space in front of each character with the help of regular expression and uses componentsSeparatedByString with <space> to return an array
Swift 4.2:
String to Array
let list = "Karin, Carrie, David"
let listItems = list.components(separatedBy: ", ")
Output : ["Karin", "Carrie", "David"]
Array to String
let list = ["Karin", "Carrie", "David"]
let listStr = list.joined(separator: ", ")
Output : "Karin, Carrie, David"
In Swift, this becomes very simple.
Swift 3:
myString.characters.map { String($0) }
Swift 4:
myString.map { String($0) }