How to pad NSString with spaces? - objective-c

For example, I need the NSString have at least 8 chars....instead of using a loop to add the left pad spaces on this, is there anyway to do it?
Examples:
Input: |Output:
Hello | Hello
Bye | Bye
Very Long |Very Long
abc | abc

Here is an example of how you can do it:
int main (int argc, const char * argv[]) {
NSString *str = #"Hello";
int add = 8-[str length];
if (add > 0) {
NSString *pad = [[NSString string] stringByPaddingToLength:add withString:#" " startingAtIndex:0];
str = [pad stringByAppendingString:str];
}
NSLog(#"'%#'", str);
return 0;
}

I just do something like this:
NSLog(#"%*c%#", 14 - theString.length, ' ', theString);
Moreover, 14is the width that you want.

You can use C language printf formatting with -[NSMutableString appendFormat:] and all other NSString "format" methods. It doesn't respect NSString (do formatting on %#), so you need to convert them to ASCII.
String Padding in C
- (NSString *)sample {
NSArray<NSString *> *input = #[#"Hello", #"Bye", #"Very Long", #"abc"];
NSMutableString *output = [[NSMutableString alloc] init];
for (NSString *string in input) {
[output appendFormat:#"%8s\n", string.UTF8String];
}
return output;
}
/*
Return value:
Hello
Bye
Very Long
abc
*/

if you need the same answer in a method, I had to create one for use in my projects. original code by dashblinkenlight
- (NSString *) LeftPadString: (NSString*) originalString LengthAfterPadding: (int)len paddingCharacter: (char) pad
{
int add = (int) (len - originalString.length);
NSString* paddingCharString = [NSString stringWithFormat:#"%c" , pad];
if (add > 0)
{
NSString *pad = [[NSString string] stringByPaddingToLength:add withString: paddingCharString startingAtIndex:0];
return [pad stringByAppendingString:originalString];
}
else
return originalString;
}

Related

Simple Objective C program - It can't be this complex

I'm in the process of learning Objective C and decided to create a simple command line program. The idea is that is asks you for your name and then displays it backwards, capitalizing the first letter of each word. I got it done but the solution seems overly complex. I can't help but feel there is a better way.
char word [256];
printf("What is your name: ");
scanf("%[^\n]s",word);
// Convert the char array to NSString
NSString * inputString = [[NSString alloc] initWithCString: word encoding: NSUTF8StringEncoding];
//This will be our output string
//NSString *nameReversed = [[NSString alloc] init]; //alloc, init are needed to create an instance of this object
NSString *nameReversed = #"";
// Make inputString all lower case
inputString = [inputString lowercaseString];
// Get length of inputString and type cast it as an int and decrement by one
int length = (int)([inputString length])-1;
BOOL foundSpace = NO;
for (int i = 0; i<=(length); i++) {
// Setup the range
NSRange range = NSMakeRange(length-i,1);
// Get the a char from the input string
NSString *inputChar = [inputString substringWithRange:range];
// If this is the first char then make it upper case
if (i==0) {
inputChar = [inputChar capitalizedString];
}
// See if the last char was a space and if so make this char upper case
if (foundSpace){
foundSpace = NO; // Reset foundSpace
// Set this char to upper case
inputChar = [inputChar capitalizedString];
}
// See if this char is a space. If so, we'll need to convert the next char to upper case
if ([inputChar isEqual: #" "]) {
foundSpace = YES;
}
// Add the char to nameReversed
nameReversed = [nameReversed stringByAppendingString:inputChar];
}
printf("%s \n", [nameReversed UTF8String]);
Any insight would be appreciated!
Your program doesn't handle composed character sequences properly.
Also, capitalizedString will capitalize the first letter of each word in the string. So you can just call it once.
static NSString *reversedString(NSString *string) {
NSMutableString *reversed = [NSMutableString stringWithCapacity:string.length];
[string enumerateSubstringsInRange:NSMakeRange(0, string.length)
options:NSStringEnumerationReverse
| NSStringEnumerationByComposedCharacterSequences
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
[reversed appendString:substring];
}];
return reversed;
}
int main(int argc, const char * argv[])
{
#autoreleasepool {
NSData *inputData = [[NSFileHandle fileHandleWithStandardInput] readDataToEndOfFile];
NSString *original = [[NSString alloc] initWithData:inputData encoding:NSUTF8StringEncoding];
NSString *reversed = reversedString(original);
NSString *reversedAndCapitalized = [reversed capitalizedString];
printf("%s\n", reversedAndCapitalized.UTF8String);
}
return 0;
}
In a real app I'd probably add a category on NSString defining a reversedString method, instead of making it a free function.
If you assume the input is in ascii encoding.
char word [256];
printf("What is your name: ");
scanf("%[^\n]s", word);
// reverse
for (NSInteger i=0,j=strlen(word)-1; i<j; i++,j--) {
char tmp = word[i];
word[i] = word[j];
word[j] = tmp;
}
NSString *str0 = [NSString stringWithCString:word encoding:NSASCIIStringEncoding];
NSLog(#"%#", [str0 capitalizedString]);

How do I format a string to Credit card format

What is the easiest way to format a string "1234567890123456789" to "1234 5678 9012 3456 789" in IOS?
Try this:
-(NSString *) correctString:(NSString *) anyStr {
NSMutableString *str=[NSMutableString stringWithString:anyStr];
int indx=4;
while (indx<str.length) {
[str insertString:#" " atIndex:indx];
indx +=5;
}
anyStr=str;
return anyStr;
}
For that particular format, you could do something like the following, which extracts the individual substrings:
NSString *string = #"1234567890123456789";
NSMutableArray *array = [NSMutableArray array];
for (NSInteger i = 0; i < [string length]; i += 4)
[array addObject:[string substringWithRange:NSMakeRange(i, MIN(4, [string length] - i))]];
NSString *result = [array componentsJoinedByString:#" "];
The thing is, not all credit cards conform to the xxxx xxxx xxxx xxxx format. E.g., Amex uses a xxxx xxxxxx xxxxx format. You really should look at the first digits of the card, determine the type of card, and format it accordingly.
You asked if you could do it with a regular expression. Consider this regex:
NSString *result = [string stringByReplacingOccurrencesOfString:#"^[\\s-]*([0-9]{4})[\\s-]*([0-9]{4})[\\s-]*([0-9]{4})[\\s-]*([0-9]{4})[\\s-]*([0-9]{3})[\\s-]*$"
withString:#"$1 $2 $3 $4 $5"
options:NSRegularExpressionSearch
range:NSMakeRange(0, [string length])];
That will convert any of the following:
#"1234567890123456789"
#"1234-5678-9012-3456-789"
#" 1234567890123456789 "
into:
#"1234 5678 9012 3456 789"
While you could use regular expression, it's sufficiently opaque that I wouldn't particularly advise it. But it can be done.
I wrote code.
NSMutableString *string = #"1234567890123456789";
NSInteger *ip = 4;
for (NSInteger i = 0; i*4 < [string length] ; i++)
{
[string insertString:#" " atIndex:ip];
ip = ip+5;
}
I propose to use NSString category. In not ARC just add autorelease after self copy.
My variant will not add spaces after last digits quarter if it is not nescessary.
Applicable to use in UITextField.
- (NSString *)creditCardNumberFormatedString {
NSString *string = [self copy];
NSUInteger length = string.length;
if (length >= 17) {
string = [string substringToIndex:16];
length = 16;
}
BOOL isSpaceRequired = YES;
if (length == 4) {
isSpaceRequired = NO;
}
NSString *newString = [NSString new];
while (string.length > 0) {
NSString *subString = [string substringToIndex:MIN(string.length, 4)];
newString = [newString stringByAppendingString:subString];
if (subString.length == 4 && isSpaceRequired) {
newString = [newString stringByAppendingString:#" "];
}
string = [string substringFromIndex:MIN(string.length, 4)];
if (string.length <= 4) {
isSpaceRequired = NO;
}
}
return newString;
}
Here is a Swift extension:
extension String {
var pairs: [String] {
var result: [String] = []
let chars = Array(characters)
for index in 0.stride(to: chars.count, by: 4) {
result.append(String(chars[index..<min(index+4, chars.count)]))
}
return result
}
}
To use:
let string : String = "1234567890123456789"
let finalString = string.pairs.joinWithSeparator(" ") //1234 5678 9012 3456 789
print(finalString)
For Swift 3:
extension String {
var pairs: [String] {
var result: [String] = []
let chars = Array(characters)
for index in stride(from: 0, to: chars.count, by: 4){
result.append(String(chars[index..<min(index+4, chars.count)]))
}
return result
}
}

Best way to split integers in Objective C

If I have this:
int toSplit = 208;
What's the best way to split it so I get:
2
0
8
Method would be like this
- (NSMutableArray *) toCharArray : (NSString *) str
{
NSMutableArray *characters = [[NSMutableArray alloc] initWithCapacity:[str length]];
for (int i=0; i < [str length]; i++)
{
NSString *ichar = [NSString stringWithFormat:#"%c", [str characterAtIndex:i]];
[characters addObject:ichar];
}
return characters;
}
do {
int digit = toSplit % 10;
toSplit /= 10;
printf(#"%i", digit);
} while (toSplit > 0);
I hope it's not a homework.
EDIT: it's backwards so it's not a valid answer... However, leaving it here because it can still be useful for others.
Sort it into a string then pull it apart. So like this:
int toSplit = 208;
NSString *string = [NSString stringWithFormat: #"%i", toSplit];
NSMutableString *splitApartString = [[NSMutableString alloc] init];
for (int i = 0; i < [string length]; i++) {
NSString *substring = [string substringFromIndex: i];
[splitApartString appendFormat: #"%#\n", substring];
}
NSLog(#"%#", splitApartString); //YAY!
So what this does, is puts this int into a string, splits it apart, then iterates through each character and gets a string out of that character. Then it appends that substring to a NEW string.
Another alternative, is instead of getting a substring just get the char and use the %c operator. Also if you take a look at this code you will see this output:
> 2
> 0
> 8
> // extra space here
You could just add a condition to check if i is the string length - 1 and not add a space or you could just remove the last character!
I'm not familiar with Objective-C syntax, but something like:
void split(int toSplit)
{
if (!toSplit)
{
return;
}
split(toSplit / 10);
int digit = toSplit % 10;
printf(#"%i", digit);
}

Substring to nth character

I need to substring to the 2nd comma in an NSString.
Input:
NSString *input = #"title, price, Camry, $19798, active";
Desired Output:
NSString *output = #"title, price";
Thanks!
UPDATE:
I have the following but the problem is it needs to skip the last comma:
NSString *output = [input rangeOfString:#"," options:NSBackwardsSearch];
Try this:
- (NSString *)substringOfString:(NSString *)base untilNthOccurrence:(NSInteger)n ofString:(NSString *)delim
{
NSScanner *scanner = [NSScanner scannerWithString:base];
NSInteger i;
for (i = 0; i < n; i++)
{
[scanner scanUpToString:delim intoString:NULL];
[scanner scanString:delim intoString:NULL];
}
return [base substringToIndex:scanner.scanLocation - delim.length];
}
this code should do what you need:
NSString *input = #"title, price, Camry, $19798, active";
NSArray *array = [input componentsSeparatedByString:#","];
NSArray *subArray = [array subarrayWithRange:NSMakeRange(0, 2)];
NSString *output = [subArray componentsJoinedByString:#","];
NSLog(output);
You could split -> splice -> join that string like this in objc:
NSString *input = #"title, price, Camry, $19798, active";
// split by ", "
NSArray *elements = [input componentsSeparatedByString: #", "];
// grab the subarray
NSArray *subelements = [elements subarrayWithRange: NSMakeRange(0, 2)];
// concat by ", " again
NSString *output = [subelements componentsJoinedByString:#", "];
You can try something like this:
NSArray *items = [list componentsSeparatedByString:#", "];
NSString result = #"";
result = [result stringByAppendingString:[items objectAtIndex:0]];
result = [result stringByAppendingString:#", "];
result = [result stringByAppendingString:[items objectAtIndex:1]];
You have to check you have at least two items if you want avoid an exception.
There's really nothing wrong with simply writing the code to do what you want. Eg:
int commaCount = 0;
int i;
for (i = 0; i < input.count; i++) {
if ([input characterAtIndex:i] == (unichar) ',') {
commaCount++;
if (commaCount == 2) break;
}
}
NSString output = nil;
if (commaCount == 2) {
output = [input substringToIndex:i];
}
You could create an NSString category to handle finding nth occurrences of any string. This is example is for ARC.
//NSString+MyExtension.h
#interface NSString(MyExtension)
-(NSString*)substringToNthOccurrence:(NSUInteger)nth
ofString:(NSString*)string;
-(NSString*)substringToNthOccurrence:(NSUInteger)nth
ofString:(NSString*)string
options:(NSStringCompareOptions)options;
#end
#implementation NSString(MyExtension)
-(NSString*)substringToNthOccurrence:(NSUInteger)nth
ofString:(NSString*)string
{
return [self substringToNthOccurrence:nth ofString:string options:0];
}
-(NSString*)substringToNthOccurrence:(NSUInteger)nth
ofString:(NSString*)string
options:(NSStringCompareOptions)options
{
NSUInteger location = 0,
strlength = [string length],
mylength = [self length];
NSRange range = NSMakeRange(location, mylength);
while(nth--)
{
location = [self rangeOfString:string
options:options
range:range].location;
if(location == NSNotFound || (location + strlength) > mylength)
{
return [self copy]; //nth occurrence not found
}
if(nth == 0) strlength = 0; //This prevents the last occurence from being included
range = NSMakeRange(location + strlength, mylength - strlength - location);
}
return [self substringToIndex:location];
}
#end
//main.m
#import "NSString+MyExtension.h"
int main(int argc, char *argv[])
{
#autoreleasepool {
NSString *output = [#"title, price, Camry, $19798, active" substringToNthOccurrence:2 ofString:#","];
NSLog(#"%#", output);
}
}
*I'll leave it as an exercise for someone to implement the mutable versions.

Separate digits in an NSString to display a phone number

I have an NSString that holds something like this:
4434332124
How can I make that into something like this?
443-433-2124
This can be done in only two lines just use NSString's stringWithFormat method and chop up the phone number into individual substrings and glue the whole thing together in your format string. Something like this:
NSString *sPhone = #"4434332124";
NSString *formatted = [NSString stringWithFormat: #"%#-%#-%#", [sPhone substringWithRange:NSMakeRange(A,B)],[sPhone substringWithRange:NSMakeRange(B,C)],
[sPhone substringWithRange:NSMakeRange(C,D)]];
EDIT: Working Code
NSString *formatted = [NSString stringWithFormat: #"%#-%#-%#", [sPhone substringWithRange:NSMakeRange(0,3)],[sPhone substringWithRange:NSMakeRange(3,3)],
[sPhone substringWithRange:NSMakeRange(6,4)]];
If you want to just do a simple quick replacement on what you are sure is a 10 digit number then try this regex example (iOS >= 3.2).
NSString *tenDigitNumber = #"5554449999";
tenDigitNumber = [tenDigitNumber stringByReplacingOccurrencesOfString:#"(\\d{3})(\\d{3})(\\d{4})"
withString:#"$1-$2-$3"
options:NSRegularExpressionSearch
range:NSMakeRange(0, [tenDigitNumber length])];
NSLog(#"%#", tenDigitNumber);
Not as pretty as trying to do something with NSFormatter (though unless you subclass it I didn't see an obvious way to get it to do something like phone numbers) but you could do this:
NSString* newString = [NSString stringWithFormat:#"%c%c%c-%c%c%c-%c%c%c%c" [phoneNumber characterAtIndex:0],
[phoneNumber characterAtIndex:1],
[phoneNumber characterAtIndex:2],
[phoneNumber characterAtIndex:3],
[phoneNumber characterAtIndex:4],
[phoneNumber characterAtIndex:5],
[phoneNumber characterAtIndex:6],
[phoneNumber characterAtIndex:7],
[phoneNumber characterAtIndex:8],
[phoneNumber characterAtIndex:9]];
#import <Foundation/Foundation.h>
static NSString * const theInString = #"4434332124";
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
const char * theUniChar = theInString.UTF8String;
NSMurableString * theResult = nil;
for( int i = 0, c = (int)strlen(theUniChar); i < c; i+=2 )
{
char thePart[4];
sscanf( theUniChar + i, "%3s", &thePart );
if( theResult == nil )
theResult = [NSMutableString string];
else
[theResult appendFormate:#"-%3s",thePart];
}
printf( "%#\n", theResult );
[pool drain];
return 0;
}