Index of a character from the NSString in iOS - ios

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);
}

Related

Scan for numbers in Objective - C

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 <> ''"]]);

NSString append WhiteSpace for every 4 Character

I have a string like #"1234123412341234", i need to append space between every 4 chars like.
#"1234 1234 1234 1234"
i.e, I need a NSString like Visa Card Type. I have tried like this but i didn't get my result.
-(void)resetCardNumberAsVisa:(NSString*)aNumber
{
NSMutableString *s = [aNumber mutableCopy];
for(int p=0; p<[s length]; p++)
{
if(p%4==0)
{
[s insertString:#" " atIndex:p];
}
}
NSLog(#"%#",s);
}
Here's a unicode aware implementation as a category on NSString:
#interface NSString (NRStringFormatting)
- (NSString *)stringByFormattingAsCreditCardNumber;
#end
#implementation NSString (NRStringFormatting)
- (NSString *)stringByFormattingAsCreditCardNumber
{
NSMutableString *result = [NSMutableString string];
__block NSInteger count = -1;
[self enumerateSubstringsInRange:(NSRange){0, [self length]}
options:NSStringEnumerationByComposedCharacterSequences
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
if ([substring rangeOfCharacterFromSet:[NSCharacterSet whitespaceCharacterSet]].location != NSNotFound)
return;
count += 1;
if (count == 4) {
[result appendString:#" "];
count = 0;
}
[result appendString:substring];
}];
return result;
}
#end
Try it with this test string:
NSString *string = #"ab 😗😌 132487 387 e e e ";
NSLog(#"%#", [string stringByFormattingAsCreditCardNumber]);
The method works with non-BMP characters (i.e. emoji) and handles existing white space.
Your code is pretty close, however a better semantic for the method is to return a new NSString for any given input string:
-(NSString *)formatStringAsVisa:(NSString*)aNumber
{
NSMutableString *newStr = [NSMutableString new];
for (NSUInteger i = 0; i < [aNumber length]; i++)
{
if (i > 0 && i % 4 == 0)
[newStr appendString:#" "];
unichar c = [aNumber characterAtIndex:i];
[newStr appendString:[[NSString alloc] initWithCharacters:&c length:1]];
}
return newStr;
}
You should do like this:
- (NSString *)resetCardNumberAsVisa:(NSString*)originalString {
NSMutableString *resultString = [NSMutableString string];
for(int i = 0; i<[originalString length]/4; i++)
{
NSUInteger fromIndex = i * 4;
NSUInteger len = [originalString length] - fromIndex;
if (len > 4) {
len = 4;
}
[resultString appendFormat:#"%# ",[originalString substringWithRange:NSMakeRange(fromIndex, len)]];
}
return resultString;
}
UPDATE:
You code will be right on the first inserting space charactor:
This is your originalString:
Text: 123412341234
Location: 012345678901
Base on your code, on the first you insert space character, you will insert at "1" (with location is 4)
And after that, your string is:
Text: 1234 12341234
Location: 0123456789012
So, you see it, now you have to insert second space charater at location is 9 (9%4 != 0)
Hope you can fix your code by yourself!
The code snippet from here do what do you want:
- (NSString *)insertSpacesEveryFourDigitsIntoString:(NSString *)string
andPreserveCursorPosition:(NSUInteger *)cursorPosition
{
NSMutableString *stringWithAddedSpaces = [NSMutableString new];
NSUInteger cursorPositionInSpacelessString = *cursorPosition;
for (NSUInteger i=0; i<[string length]; i++) {
if ((i>0) && ((i % 4) == 0)) {
[stringWithAddedSpaces appendString:#" "];
if (i < cursorPositionInSpacelessString) {
(*cursorPosition)++;
}
}
unichar characterToAdd = [string characterAtIndex:i];
NSString *stringToAdd =
[NSString stringWithCharacters:&characterToAdd length:1];
[stringWithAddedSpaces appendString:stringToAdd];
}
return stringWithAddedSpaces;
}
swift3 based on Droppy
func codeFormat(_ code: String) -> String {
let newStr = NSMutableString()
for i in 0..<code.characters.count {
if (i > 0 && i % 4 == 0){
newStr.append(" ")
}
var c = (code as NSString).character(at: i)
newStr.append(NSString(characters: &c, length: 1) as String)
}
return newStr as String
}
Please make sure that your string length should times by 4.
This solution will insert on the right hand side first.
- (NSString*) fillWhiteGapWithString:(NSString*)source
{
NSInteger dl = 4;
NSMutableString* result = [NSMutableString stringWithString:source];
for(NSInteger cnt = result.length - dl ; cnt > 0 ; cnt -= dl)
{
[result insertString:#" " atIndex:cnt];
}
return result;
}

Return NSRegularexpression results in an array

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];
}

Replace using regular expression with replacement function

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++++---

How can i calculate the total number of words and character in textView? [duplicate]

This question already has answers here:
Objective-C: -[NSString wordCount]
(7 answers)
Closed 9 years ago.
i am using the following code to calculate the total number of words
-(NSInteger) getTotalWords{
NSLog(#"Total Word %lu",[[_editor.attributedText string]length]);
if ([[_editor.attributedText string]length]==0) {
return 0;
}
NSString *str =[_editor textInRange:[_editor textRangeWithRange:[self visibleRangeOfTextView:_editor]]];
NSInteger sepWord = [[[str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]componentsSeparatedByString:#" "] count];
sepWord += [[[str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]componentsSeparatedByString:#"\n"] count];
sepWord=sepWord-2;
return sepWord;
}
and here is the code for the total character
-(NSInteger) getTotalChars{
NSString *str =[_editor textInRange:[_editor textRangeWithRange:[self visibleRangeOfTextView:_editor]]];
NSLog(#"%#",str);
NSInteger charCount= [[str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]length];
return charCount=charCount-1;
}
But i m not getting the perfect count when i enter more than two lines. it takes new line as word..
please help..!!!
If you really want to count words (i.e. "foo,bar" should count as 2 words with
6 characters) then
you can use the NSStringEnumerationByWords option of enumerateSubstringsInRange,
which handles all the white space and word separators automatically:
NSString *string = #"Hello world.\nfoo,bar.";
__block int wordCount = 0;
__block int charCount = 0;
[string enumerateSubstringsInRange:NSMakeRange(0, [string length])
options:NSStringEnumerationByWords
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
wordCount += 1;
charCount += substringRange.length;
}];
NSLog(#"%d", wordCount); // Output: 4
NSLog(#"%d", charCount); // Output: 16
You could simply do:
NSString *text = #"Lorem ...";
NSArray *words = [text componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSInteger wordCount = [words count];
NSInteger characterCount = 0;
for (NSString *word in words) {
characterCount += [word length];
}
once try like this,
NSString *string = #"123 1 2\n234\nponies";
NSArray *chunks = [string componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#" \n"]];
NSLog(#"%d",[chunks count]);
for word count...
NSString *str = #"this is a sample string....";
NSScanner *scanner = [NSScanner scannerWithString:str];
NSCharacterSet *whiteSpace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
NSCharacterSet *nonWhitespace = [whiteSpace invertedSet];
int wordcount = 0;
while(![scanner isAtEnd])
{
[scanner scanUpToCharactersFromSet:nonWhitespace intoString:nil];
[scanner scanUpToCharactersFromSet:whitespace intoString:nil];
wordcount++;
}
int characterCount = 0;
For getting word count use -
NSArray *array = [txtView.text componentsSeparatedByString:#" "];
int wordCount = [array count];
for(int i = 0; i < [array count]; i++){
characterCount = characterCount + [[array objectAtIndex:i] length];
}
NSLog(#"characterCount : %i",characterCount);
NSLog(#"wordCount : %i",wordCount);
str = textView.text;
NSArray *wordArray = [str componentsSeparatedByString:#" "];
int wordCount = [wordArray count];
int charCount=0;
for (int i=0 ; i < [wordArray count]; i++)
{
charCount = charCount + [[wordArray objectAtIndex:0] length];
}

Resources