Replace characters in NSString - objective-c

I am trying to replace all characters except last 4 in a String with *'s.
In objective-c there is a method in NSString class replaceStringWithCharactersInRange: withString: where I would give it range (0,[string length]-4) ) with string #"*". This is what it does: 123456789ABCD is modified to *ABCD while I am looking to make ********ABCD.
I understand that it replaced range I specified with string object. How to accomplish this ?

NSError *error;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"\\d" options:NSRegularExpressionCaseInsensitive error:&error];
NSString *newString = [regex stringByReplacingMatchesInString:string options:0 range:NSMakeRange(0, [string length]) withTemplate:#"*"];

This looks like a simple problem... get the first part string and return it with the last four characters appended to it.
Here is a function that returns the needed string :
-(NSString *)neededStringWithString:(NSString *)aString {
// if the string has less than or 4 characters, return nil
if([aString length] <= 4) {
return nil;
}
NSUInteger countOfCharToReplace = [aString length] - 4;
NSString *firstPart = #"*";
while(--countOfCharToReplace) {
firstPart = [firstPart stringByAppendingString:#"*"];
}
// range for the last four
NSRange lastFourRange = NSMakeRange([aString length] - 4, 4);
// return the combined string
return [firstPart stringByAppendingString:
[aString substringWithRange:lastFourRange]];
}

The most unintuitive part in Cocoa is creating the repeating stars without some kind of awkward looping. stringByPaddingToLength:withString:startingAtIndex: allows you to create a repeating string of any length you like, so once you have that, here's a simple solution:
NSInteger starUpTo = [string length] - 4;
if (starUpTo > 0) {
NSString *stars = [#"" stringByPaddingToLength:starUpTo withString:#"*" startingAtIndex:0];
return [string stringByReplacingCharactersInRange:NSMakeRange(0, starUpTo) withString:stars];
} else {
return string;
}

I'm not sure why the accepted answer was accepted, since it only works if everything but last 4 is a digit. Here's a simple way:
NSMutableString * str1 = [[NSMutableString alloc]initWithString:#"1234567890ABCD"];
NSRange r = NSMakeRange(0, [str1 length] - 4);
[str1 replaceCharactersInRange:r withString:[[NSString string] stringByPaddingToLength:r.length withString:#"*" startingAtIndex:0]];
NSLog(#"%#",str1);

You could use [theString substringToIndex:[theString length]-4] to get the first part of the string and then combine [theString length]-4 *'s with the second part. Perhaps their is an easier way to do this..

NSMutableString * str1 = [[NSMutableString alloc]initWithString:#"1234567890ABCD"];
[str1 replaceCharactersInRange:NSMakeRange(0, [str1 length] - 4) withString:#"*"];
NSLog(#"%#",str1);
it works

The regexp didn't work on iOS7, but perhaps this helps:
- (NSString *)encryptString:(NSString *)pass {
NSMutableString *secret = [NSMutableString new];
for (int i=0; i<[pass length]; i++) {
[secret appendString:#"*"];
}
return secret;
}
In your case you should stop replacing the last 4 characters. Bit crude, but gets the job done

Related

Take all numbers separated by spaces from a string and place in an array

I have a NSString formatted like this:
"Hello world 12 looking for some 56"
I want to find all instances of numbers separated by whitespace and place them in an NSArray. I dont want to remove the numbers though.
Whats the best way of achieving this?
This is a solution using regular expression as suggested in the comment.
NSString *string = #"Hello world 12 looking for some 56";
NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:#"\\b\\d+" options:nil error:nil];
NSArray *matches = [expression matchesInString:string options:nil range:(NSMakeRange(0, string.length))];
NSMutableArray *result = [[NSMutableArray alloc] init];
for (NSTextCheckingResult *match in matches) {
[result addObject:[string substringWithRange:match.range]];
}
NSLog(#"%#", result);
First make an array using NSString's componentsSeparatedByString method and take reference to this SO question. Then iterate the array and refer to this SO question to check if an array element is number: Checking if NSString is Integer.
I don't know where you are looking to do perform this action because it may not be fast (such as if it's being called in a table cell it may be choppy) based upon the string size.
Code:
+ (NSArray *)getNumbersFromString:(NSString *)str {
NSMutableArray *retVal = [NSMutableArray array];
NSCharacterSet *numericSet = [NSCharacterSet decimalDigitCharacterSet];
NSString *placeholder = #"";
unichar currentChar;
for (int i = [str length] - 1; i >= 0; i--) {
currentChar = [str characterAtIndex:i];
if ([numericSet characterIsMember:currentChar]) {
placeholder = [placeholder stringByAppendingString:
[NSString stringWithCharacters:&currentChar
length:[placeholder length]+1];
} else {
if ([placeholder length] > 0) [retVal addObject:[placeholder intValue]];
else placeholder = #"";
return [retVal copy];
}
To explain what is happening above, essentially I am,
going through every character until I find a number
adding that number including any numbers after to a string
once it finds a number it adds it to an array
Hope this helps please ask for clarification if needed

Check if NSString only contains one character repeated

I want to know a simple and fast way to determine if all characters in an NSString are the same.
For example:
NSString *string = "aaaaaaaaa"
=> return YES
NSString *string = "aaaaaaabb"
=> return NO
I know that I can achieve it by using a loop but my NSString is long so I prefer a shorter and simpler way.
you can use this, replace first character with null and check lenght:
-(BOOL)sameCharsInString:(NSString *)str{
if ([str length] == 0 ) return NO;
return [[str stringByReplacingOccurrencesOfString:[str substringToIndex:1] withString:#""] length] == 0 ? YES : NO;
}
Here are two possibilities that fail as quickly as possible and don't (explicitly) create copies of the original string, which should be advantageous since you said the string was large.
First, use NSScanner to repeatedly try to read the first character in the string. If the loop ends before the scanner has reached the end of the string, there are other characters present.
NSScanner * scanner = [NSScanner scannerWithString:s];
NSString * firstChar = [s substringWithRange:[s rangeOfComposedCharacterSequenceAtIndex:0]];
while( [scanner scanString:firstChar intoString:NULL] ) continue;
BOOL stringContainsOnlyOneCharacter = [scanner isAtEnd];
Regex is also a good tool for this problem, since "a character followed by any number of repetitions of that character" is in very simply expressed with a single back reference:
// Match one of any character at the start of the string,
// followed by any number of repetitions of that same character
// until the end of the string.
NSString * patt = #"^(.)\\1*$";
NSRegularExpression * regEx =
[NSRegularExpression regularExpressionWithPattern:patt
options:0
error:NULL];
NSArray * matches = [regEx matchesInString:s
options:0
range:(NSRange){0, [s length]}];
BOOL stringContainsOnlyOneCharacter = ([matches count] == 1);
Both these options correctly deal with multi-byte and composed characters; the regex version also does not require an explicit check for the empty string.
use this loop:
NSString *firstChar = [str substringWithRange:NSMakeRange(0, 1)];
for (int i = 1; i < [str length]; i++) {
NSString *ch = [str substringWithRange:NSMakeRange(i, 1)];
if(![ch isEqualToString:firstChar])
{
return NO;
}
}
return YES;

Objective-C regex to remove part of string

Hi im trying to remove som HTML string from a web response. I want to remove <pre><a style="" name="output-line-1">1</a>, were the who instances of number "1"varies, but is always a digit. but how do i write the regex method for removing this? Below is what i have got so far:
-(NSString *)stringByStrippingHTML:(NSString*)str
{
NSRange r;
while ((r = [str rangeOfString:#"/^<pre><a style=\"\"name=\"output-line-([0-9])\">([0-9])</a>" options:NSRegularExpressionSearch]).location != NSNotFound){
str = [str stringByReplacingCharactersInRange:r withString:#""];
}
}
Basically I want to remove a substring with random number in it... In some instances of the substring the 1 is replaced, so that any similar string gets acknowledged, for example it could be output-line-999. How do i combine the range of string so i can both describe the string and specify to find any similar string with any number?
I want to remove both the HTML and the numbers.
This regular expression should work:
[str rangeOfString:#"<pre><a style=\"\" name=\"output-line-[0-9]+\">[0-9]+</a>" options:NSRegularExpressionSearch];
I thnk the problem is that there ins't a space before name in your reg expression
Using your original while loop, you can:
-(NSString *)stringByStrippingHTML:(NSString*)str
{
NSRange r;
while ((r = [str rangeOfString:#"<pre><a style=\"\" name=\"output-line-[0-9]+\">[0-9]+</a>" options:NSRegularExpressionSearch]).location != NSNotFound)
{
str = [str stringByReplacingCharactersInRange:r withString:#""];
}
}
Or you can use NSRegularExpression:
NSMutableString *input = ...
NSError *error;
NSRegularExpression *regex;
regex = [NSRegularExpression regularExpressionWithPattern:#"<pre><a style=\"\" name=\"output-line-[0-9]+\">[0-9]+</a>"
options:0
error:&error];
if (error)
{
NSLog(#"error=%#",error);
return;
}
[regex replaceMatchesInString:input
options:0
range:NSMakeRange(0, [input length])
withTemplate:#""];

Replace specific words in NSString

what is the best way to get and replace specific words in string ?
for example I have
NSString * currentString = #"one {two}, thing {thing} good";
now I need find each {currentWord}
and apply function for it
[self replaceWord:currentWord]
then replace currentWord with result from function
-(NSString*)replaceWord:(NSString*)currentWord;
The following example shows how you can use NSRegularExpression and enumerateMatchesInString to accomplish the task. I have just used uppercaseString as function that replaces a word, but you can use your replaceWord method as well:
EDIT: The first version of my answer did not work correctly if the replaced words are
shorter or longer as the original words (thanks to Fabian Kreiser for noting that!) .
Now it should work correctly in all cases.
NSString *currentString = #"one {two}, thing {thing} good";
// Regular expression to find "word characters" enclosed by {...}:
NSRegularExpression *regex;
regex = [NSRegularExpression regularExpressionWithPattern:#"\\{(\\w+)\\}"
options:0
error:NULL];
NSMutableString *modifiedString = [currentString mutableCopy];
__block int offset = 0;
[regex enumerateMatchesInString:currentString
options:0
range:NSMakeRange(0, [currentString length])
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
// range = location of the regex capture group "(\\w+)" in currentString:
NSRange range = [result rangeAtIndex:1];
// Adjust location for modifiedString:
range.location += offset;
// Get old word:
NSString *oldWord = [modifiedString substringWithRange:range];
// Compute new word:
// In your case, that would be
// NSString *newWord = [self replaceWord:oldWord];
NSString *newWord = [NSString stringWithFormat:#"--- %# ---", [oldWord uppercaseString] ];
// Replace new word in modifiedString:
[modifiedString replaceCharactersInRange:range withString:newWord];
// Update offset:
offset += [newWord length] - [oldWord length];
}
];
NSLog(#"%#", modifiedString);
Output:
one {--- TWO ---}, thing {--- THING ---} good

How to capitalize the first word of the sentence in Objective-C?

I've already found how to capitalize all words of the sentence, but not the first word only.
NSString *txt =#"hi my friends!"
[txt capitalizedString];
I don't want to change to lower case and capitalize the first char. I'd like to capitalize the first word only without change the others.
Here is another go at it:
NSString *txt = #"hi my friends!";
txt = [txt stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[txt substringToIndex:1] uppercaseString]];
For Swift language:
txt.replaceRange(txt.startIndex...txt.startIndex, with: String(txt[txt.startIndex]).capitalizedString)
The accepted answer is wrong. First, it is not correct to treat the units of NSString as "characters" in the sense that a user expects. There are surrogate pairs. There are combining sequences. Splitting those will produce incorrect results. Second, it is not necessarily the case that uppercasing the first character produces the same result as capitalizing a word containing that character. Languages can be context-sensitive.
The correct way to do this is to get the frameworks to identify words (and possibly sentences) in the locale-appropriate manner. And also to capitalize in the locale-appropriate manner.
[aMutableString enumerateSubstringsInRange:NSMakeRange(0, [aMutableString length])
options:NSStringEnumerationByWords | NSStringEnumerationLocalized
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
[aMutableString replaceCharactersInRange:substringRange
withString:[substring capitalizedStringWithLocale:[NSLocale currentLocale]]];
*stop = YES;
}];
It's possible that the first word of a string is not the same as the first word of the first sentence of a string. To identify the first (or each) sentence of the string and then capitalize the first word of that (or those), then surround the above in an outer invocation of -enumerateSubstringsInRange:options:usingBlock: using NSStringEnumerationBySentences | NSStringEnumerationLocalized. In the inner invocation, pass the substringRange provided by the outer invocation as the range argument.
Use
- (NSArray *)componentsSeparatedByCharactersInSet:(NSCharacterSet *)separator
and capitalize the first object in the array and then use
- (NSString *)componentsJoinedByString:(NSString *)separator
to join them back
pString = [pString
stringByReplacingCharactersInRange:NSMakeRange(0,1)
withString:[[pString substringToIndex:1] capitalizedString]];
you can user with regular expression i have done it's works for me simple you can paste below code
+(NSString*)CaptializeFirstCharacterOfSentence:(NSString*)sentence{
NSMutableString *firstCharacter = [sentence mutableCopy];
NSString *pattern = #"(^|\\.|\\?|\\!)\\s*(\\p{Letter})";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:NULL];
[regex enumerateMatchesInString:sentence options:0 range:NSMakeRange(0, [sentence length]) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
//NSLog(#"%#", result);
NSRange r = [result rangeAtIndex:2];
[firstCharacter replaceCharactersInRange:r withString:[[sentence substringWithRange:r] uppercaseString]];
}];
NSLog(#"%#", firstCharacter);
return firstCharacter;
}
//Call this method
NsString *resultSentence = [UserClass CaptializeFirstCharacterOfSentence:yourTexthere];
An alternative solution in Swift:
var str = "hello"
if count(str) > 0 {
str.splice(String(str.removeAtIndex(str.startIndex)).uppercaseString, atIndex: str.startIndex)
}
For the sake of having options, I'd suggest:
NSString *myString = [NSString stringWithFormat:#"this is a string..."];
char *tmpStr = calloc([myString length] + 1,sizeof(char));
[myString getCString:tmpStr maxLength:[myString length] + 1 encoding:NSUTF8StringEncoding];
int sIndex = 0;
/* skip non-alpha characters at beginning of string */
while (!isalpha(tmpStr[sIndex])) {
sIndex++;
}
toupper(tmpStr[sIndex]);
myString = [NSString stringWithCString:tmpStr encoding:NSUTF8StringEncoding];
I'm at work and don't have my Mac to test this on, but if I remember correctly, you couldn't use [myString cStringUsingEncoding:NSUTF8StringEncoding] because it returns a const char *.
In swift you can do it as followed by using this extension:
extension String {
func ucfirst() -> String {
return (self as NSString).stringByReplacingCharactersInRange(NSMakeRange(0, 1), withString: (self as NSString).substringToIndex(1).uppercaseString)
}
}
calling your string like this:
var ucfirstString:String = "test".ucfirst()
I know the question asks specifically for an Objective C answer, however here is a solution for Swift 2.0:
let txt = "hi my friends!"
var sentencecaseString = ""
for (index, character) in txt.characters.enumerate() {
if 0 == index {
sentencecaseString += String(character).uppercaseString
} else {
sentencecaseString.append(character)
}
}
Or as an extension:
func sentencecaseString() -> String {
var sentencecaseString = ""
for (index, character) in self.characters.enumerate() {
if 0 == index {
sentencecaseString += String(character).uppercaseString
} else {
sentencecaseString.append(character)
}
}
return sentencecaseString
}