Test if NSString ends with whitespace or newline character? - objective-c

How do I test if the last character of an NSString is a whitespace or newline character.
I could do [[NSCharacter whitespaceAndNewlineCharacterSet] characterIsMember:lastChar]. But, how do I get the last character of an NSString?
Or, should I just use - [NSString rangeOfCharacterFromSet:options:] with a reverse search?

You're on the right track. The following shows how you can retrieve the last character in a string; you can then check if it's a member of the whitespaceAndNewlineCharacterSet as you suggested.
unichar last = [myString characterAtIndex:[myString length] - 1];
if ([[NSCharacterSet whitespaceAndNewlineCharacterSet] characterIsMember:last]) {
// ...
}

Maybe you can use length on an NSString object to get its length and then use:
- (unichar)characterAtIndex:(NSUInteger)index
with index as length - 1. Now you have the last character which can be compared with [NSCharacter whitespaceAndNewlineCharacterSet].

#implementation NSString (Additions)
- (BOOL)endsInWhitespaceOrNewlineCharacter {
NSUInteger stringLength = [self length];
if (stringLength == 0) {
return NO;
}
unichar lastChar = [self characterAtIndex:stringLength-1];
return [[NSCharacterSet whitespaceAndNewlineCharacterSet] characterIsMember:lastChar];
}
#end

Related

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;

Remove last character of NSString

I've got some trouble 'ere trying to remove the last character of an NSString.
I'm kinda newbie in Objective-C and I have no idea how to make this work.
Could you guys light me up?
NSString *newString = [oldString substringToIndex:[oldString length]-1];
Always refer to the documentation:
substringToIndex:
length
To include code relevant to your case:
NSString *str = textField.text;
NSString *truncatedString = [str substringToIndex:[str length]-1];
Try this:
s = [s substringToIndex:[s length] - 1];
NSString *string = [NSString stringWithString:#"ABCDEF"];
NSString *newString = [string substringToIndex:[string length]-1];
NSLog(#"%#",newString);
You can see = ABCDE
NSString = *string = #"abcdef";
string = [string substringToIndex:string.length-(string.length>0)];
If there is a character to delete (i.e. the length of the string is greater than 0)
(string.length>0) returns 1, thus making the code return:
string = [string substringToIndex:string.length-1];
If there is NOT a character to delete (i.e. the length of the string is NOT greater than 0)
(string.length>0) returns 0, thus making the code return:
string = [string substringToIndex:string.length-0];
which prevents crashes.
This code will just return the last character of the string and not removing it :
NSString *newString = [oldString substringToIndex:[oldString length]-1];
you may use this instead to remove the last character and retain the remaining values of a string :
str = [str substringWithRange:NSMakeRange(0,[str length] - 1)];
and also using substringToIndex to a NSString with 0 length will result to crashes.
you should add validation before doing so, like this :
if ([str length] > 0) {
str = [str substringToIndex:[s length] - 1];
}
with this, it is safe to use substring method.
NOTE : Apple will reject your application if it is vulnerable to crashes.
Simple and Best Approach
[mutableString deleteCharactersInRange:NSMakeRange([myRequestString length]-1, 1)];

Replace characters in NSString

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

Separating NSString into NSArray, but allowing quotes to group words

I have a search string, where people can use quotes to group phrases together, and mix this with individual keywords. For example, a string like this:
"Something amazing" rooster
I'd like to separate that into an NSArray, so that it would have Something amazing (without quotes) as one element, and rooster as the other.
Neither componentsSeparatedByString nor componentsSeparatedByCharactersInSet seem to fit the bill. Is there an easy way to do this, or should I just code it up myself?
You probably will have to code some of this up yourself, but the NSScanner should be a good basis on which to build. If you use the scanUpToCharactersInSet method to look for everything up to your next whitespace or quote character to can pick off words. Once you encounter a quite character, you could continue to scan using just the quote in the character set to end at, so that spaces within the quotes don't result in the end of a token.
I made a simple way to do this using NSScanner:
+ (NSArray *)arrayFromTagString:(NSString *)string {
NSScanner *scanner = [NSScanner scannerWithString:string];
NSString *substring;
NSMutableArray *array = [[NSMutableArray alloc] init];
while (scanner.scanLocation < string.length) {
// test if the first character is a quote
unichar character = [string characterAtIndex:scanner.scanLocation];
if (character == '"') {
// skip the first quote and scan everything up to the next quote into a substring
[scanner setScanLocation:(scanner.scanLocation + 1)];
[scanner scanUpToString:#"\"" intoString:&substring];
[scanner setScanLocation:(scanner.scanLocation + 1)]; // skip the second quote too
}
else {
// scan everything up to the next space into the substring
[scanner scanUpToString:#" " intoString:&substring];
}
// add the substring to the array
[array addObject:substring];
//if not at the end, skip the space character before continuing the loop
if (scanner.scanLocation < string.length) [scanner setScanLocation:(scanner.scanLocation + 1)];
}
return array.copy;
}
This method will convert the array back to a tag string, re-quoting the multi-word tags:
+ (NSString *)tagStringFromArray:(NSArray *)array {
NSMutableString *string = [[NSMutableString alloc] init];
NSRange range;
for (NSString *substring in array) {
if (string.length > 0) {
[string appendString:#" "];
}
range = [substring rangeOfString:#" "];
if (range.location != NSNotFound) {
[string appendFormat:#"\"%#\"", substring];
}
else [string appendString:substring];
}
return string.description;
}
I ended up going with a regular expression as I was already using RegexKitLite, and creating this NSString+SearchExtensions category.
.h:
// NSString+SearchExtensions.h
#import <Foundation/Foundation.h>
#interface NSString (SearchExtensions)
-(NSArray *)searchParts;
#end
.m:
// NSString+SearchExtensions.m
#import "NSString+SearchExtensions.h"
#import "RegexKitLite.h"
#implementation NSString (SearchExtensions)
-(NSArray *)searchParts {
__block NSMutableArray *items = [[NSMutableArray alloc] initWithCapacity:5];
[self enumerateStringsMatchedByRegex:#"\\w+|\"[\\w\\s]*\"" usingBlock: ^(NSInteger captureCount,
NSString * const capturedStrings[captureCount],
const NSRange capturedRanges[captureCount],
volatile BOOL * const stop) {
NSString *result = [capturedStrings[0] stringByReplacingOccurrencesOfRegex:#"\"" withString:#""];
NSLog(#"Match: '%#'", result);
[items addObject:result];
}];
return [items autorelease];
}
#end
This returns an NSArray of strings with the search strings, removing the double quotes that surround the phrases.
If you'll allow a slightly different approach, you could try Dave DeLong's CHCSVParser. It is intended to parse CSV strings, but if you set the space character as the delimiter, I am pretty sure you will get the intended behavior.
Alternatively, you can peek into the code and see how it handles quoted fields - it is published under the MIT license.
I would run -componentsSeparatedByString:#"\"" first, then create a BOOL isPartOfQuote, initialized to YES if the first character of the string was a ", but otherwise set to NO.
Then create a mutable array to return:
NSMutableArray* masterArray = [[NSMutableArray alloc] init];
Then, create a loop over the array returned from the separation:
for(NSString* substring in firstSplitArray) {
NSArray* secondSplit;
if (isPartOfQuote == NO) {
secondSplit = [substring componentsSeparatedByString:#" "];
}
else {
secondSplit = [NSArray arrayWithObject: substring];
}
[masterArray addObjectsFromArray: secondSplit];
isPartOfQuote = !isPartOfQuote;
}
Then return masterArray from the function.

cut a char in a string

I have a string
string = "01";
but I want to delete the '0' and have a new string with only '1'. Is there a fast solution?
-(NSString *) substringFromIndex: i
Returns a substring from the character at i to the end
-(NSString *) substringWithRange: range
Returns a substring based on a specified range
-(NSString *) substringToIndex: i
Returns a substring from the start of the string up to the character at index i
And if you only want to remove 0's before any nonzero value then make a
int i = [str intValue];
str = [NSString stringWithFormat:#"%d",i];
You can use this:-
NSString *string=#"01";
NSString *temp=[string substringWithRange:NSMakeRange(1, 1)];
NSLog(#"temp%#",temp);
If you want to remove the leading zero from an arbitrary length NSString object you could do:
NSRange aRange;
aRange.location = 0;
aRange.length = 1;
[theBreakerCode stringByReplacingOccurrencesOfString:#"0" withString:#"" options:NSLiteralSearch range:aRange];
Strings without a leading zero are untouched.