Capitalize or change case of an NSString in Objective-C - objective-c

I was wondering how to capitalize a string found in an object in an NSMutableArray.
An NSArray contains the string 'April' at index 2.
I want this to be changed to 'APRIL'.
Is there something simple like this?
viewNoteDateMonth.text = [[displayDate objectAtIndex:2] capitalized];

Here ya go:
viewNoteDateMonth.text = [[displayDate objectAtIndex:2] uppercaseString];
Btw:
"april" is lowercase ➔ [NSString lowercaseString]
"APRIL" is UPPERCASE ➔ [NSString uppercaseString]
"April May" is Capitalized/Word Caps ➔ [NSString capitalizedString]
"April may" is Sentence caps ➔ (method missing; see workaround below)
Hence what you want is called "uppercase", not "capitalized". ;)
As for "Sentence Caps" one has to keep in mind that usually "Sentence" means "entire string". If you wish for real sentences use the second method, below, otherwise the first:
#interface NSString ()
- (NSString *)sentenceCapitalizedString; // sentence == entire string
- (NSString *)realSentenceCapitalizedString; // sentence == real sentences
#end
#implementation NSString
- (NSString *)sentenceCapitalizedString {
if (![self length]) {
return [NSString string];
}
NSString *uppercase = [[self substringToIndex:1] uppercaseString];
NSString *lowercase = [[self substringFromIndex:1] lowercaseString];
return [uppercase stringByAppendingString:lowercase];
}
- (NSString *)realSentenceCapitalizedString {
__block NSMutableString *mutableSelf = [NSMutableString stringWithString:self];
[self enumerateSubstringsInRange:NSMakeRange(0, [self length])
options:NSStringEnumerationBySentences
usingBlock:^(NSString *sentence, NSRange sentenceRange, NSRange enclosingRange, BOOL *stop) {
[mutableSelf replaceCharactersInRange:sentenceRange withString:[sentence sentenceCapitalizedString]];
}];
return [NSString stringWithString:mutableSelf]; // or just return mutableSelf.
}
#end

viewNoteDateMonth.text = [[displayDate objectAtIndex:2] uppercaseString];
Documentation: http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/occ/instm/NSString/uppercaseString
You can also use lowercaseString and capitalizedString

In case anyone needed the above in swift :
SWIFT 3.0 and above :
this will capitalize your string, make the first letter capital :
viewNoteDateMonth.text = yourString.capitalized
this will uppercase your string, make all the string upper case :
viewNoteDateMonth.text = yourString.uppercased()

Related

Spliting string to array by constant number

I'v been trying to split string to array of components by number, but have no idea how to do it. I know that each components lenght is 9 except the last one. But there is no separation between them. Maybe anyone would know how could i make this split possible?
string : E44000000R33000444V33441
And i'd like to get array with: E44000000 R33000444 V33441
in past I'v used this method, but i guess there should be a way to separate by constant number. Any ideas
NSArray *myWords = [message componentsSeparatedByString:#";"];
Please try the below code.
NSString *stringTest = #"E44000000R33000444V33441323";
NSMutableArray *arrayTest = [NSMutableArray array];
while([stringTest length] > 8) {
[arrayTest addObject:[NSString stringWithString:[stringTest substringToIndex:9]]];
stringTest = [stringTest substringFromIndex:9];
}
NSLog(#"arrayTest - %#", arrayTest);
Try this one..
NSString *mainString=#"E44000000R33000444V";
NSMutableArray *brokenString=[NSMutableArray new];
int start=0;
for (; start<mainString.length-9; start+=9) {
[brokenString addObject:[mainString substringWithRange:NSMakeRange(start, 9)]];
}
[brokenString addObject:[mainString substringFromIndex:start]];
NSLog(#"->%#",brokenString);
Output is :
->(
E44000000,
R33000444,
V
)
I investigated the NSString, and i didn't found any function like that. But you can create a category of NSString and put this function in that category and you can use as a NSString instance method.
- (NSArray *) componentSaparetedByLength:(NSUInteger) length{
NSMutableArray *array = [NSMutableArray new];
NSRange range = NSMakeRange(0, length);
NSString *subString = nil;
while (range.location + range.length <= self.length) {
subString = [self substringWithRange:range];
[array addObject:subString];
//Edit
range.location = range.length + range.location;
//Edit
range.length = length;
}
if(range.location<self.length){
subString = [self substringFromIndex:range.location];
[array addObject:subString];
}
return array;
}
You can get the substring upto the characters which you want in a loop(string length) & pass the next index for getting the next substring. After getting each substring you can add it to the array.
Used SubstringToIndex & SubstringFromIndex functions to get the substring.
Also not an requirement here, I want to propose a solution that is capable of handling characters from more sophisticated script systems, like surrogate pairs, base characters plus combining marks, Hangul jamo, and Indic consonant clusters.
#interface NSString (Split)
-(NSArray *)arrayBySplittingWithMaximumSize:(NSUInteger)size
options:(NSStringEnumerationOptions) option;
#end
#implementation NSString (Split)
-(NSArray *)arrayBySplittingWithMaximumSize:(NSUInteger)size
options:(NSStringEnumerationOptions) option
{
NSMutableArray *letterArray = [NSMutableArray array];
[self enumerateSubstringsInRange:NSMakeRange(0, [self length])
options:(option)
usingBlock:^(NSString *substring,
NSRange substringRange,
NSRange enclosingRange,
BOOL *stop) {
[letterArray addObject:substring];
}];
NSMutableArray *array = [NSMutableArray array];
[letterArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if (idx%size == 0) {
[array addObject: [NSMutableString stringWithCapacity:size]];
}
NSMutableString *string = [array objectAtIndex:[array count]-1];
[string appendString:obj];
}];
return array;
}
#end
usage
NSArray *array = [#"E44000000R33000444V33441" arraysBySplittingWithMaximumSize:9
options:NSStringEnumerationByComposedCharacterSequences];
results in:
(
E44000000,
R33000444,
V33441
)

iOS - Most efficient way to find word occurrence count in a string

Given a string, I need to obtain a count of each word that appears in that string. To do so, I extracted the string into an array, by word, and searched that way, but I have the feeling that searching the string directly is more optimal. Below is the code that I originally wrote to solve the problem. I'm up for suggestions on better solutions though.
NSMutableDictionary *sets = [[NSMutableDictionary alloc] init];
NSString *paragraph = [[NSString alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"text" ofType:#"txt"] encoding:NSUTF8StringEncoding error:NULL];
NSMutableArray *words = [[[paragraph lowercaseString] componentsSeparatedByString:#" "] mutableCopy];
while (words.count) {
NSMutableIndexSet *indexSet = [[NSMutableIndexSet alloc] init];
NSString *search = [words objectAtIndex:0];
for (unsigned i = 0; i < words.count; i++) {
if ([[words objectAtIndex:i] isEqualToString:search]) {
[indexSet addIndex:i];
}
}
[sets setObject:[NSNumber numberWithInt:indexSet.count] forKey:search];
[words removeObjectsAtIndexes:indexSet];
}
NSLog(#"%#", sets);
Example:
Starting string:
"This is a test. This is only a test."
Results:
"This" - 2
"is" - 2
"a" - 2
"test" - 2
"only" - 1
This is exactly what an NSCountedSet is for.
You need to break the string apart into words (which iOS is nice enough to give us a function for so that we don't have to worry about punctuation) and just add each of them to the counted set, which keeps track of the number of times each object appears in the set:
NSString *string = #"This is a test. This is only a test.";
NSCountedSet *countedSet = [NSCountedSet new];
[string enumerateSubstringsInRange:NSMakeRange(0, [string length])
options:NSStringEnumerationByWords | NSStringEnumerationLocalized
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop){
// This block is called once for each word in the string.
[countedSet addObject:substring];
// If you want to ignore case, so that "this" and "This"
// are counted the same, use this line instead to convert
// each word to lowercase first:
// [countedSet addObject:[substring lowercaseString]];
}];
NSLog(#"%#", countedSet);
// Results: 2012-11-13 14:01:10.567 Testing App[35767:fb03]
// <NSCountedSet: 0x885df70> (a [2], only [1], test [2], This [2], is [2])
If I had to guess, I would say NSRegularExpression for that. Like this:
NSUInteger numberOfMatches = [regex numberOfMatchesInString:string
options:0
range:NSMakeRange(0, [string length])];
That snippet was taken from here.
Edit 1.0:
Based on what Sir Till said:
NSString *string = #"This is a test, so it is a test";
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
NSArray *arrayOfWords = [string componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
for (NSString *word in arrayOfWords)
{
if ([dictionary objectForKey:word])
{
NSNumber *numberOfOccurences = [dictionary objectForKey:word];
NSNumber *increment = [NSNumber numberWithInt:(1 + [numberOfOccurences intValue])];
[dictionary setValue:increment forKey:word];
}
else
{
[dictionary setValue:[NSNumber numberWithInt:1] forKey:word];
}
}
You should be careful with:
Punctuation signs. (near other words)
UpperCase words vs lowerCase words.
I think that's really bad idea that you trying to search a words among the long paragraph with a loop. You should use a regular expression to do that! I know it's not easy at first time to learn it but it's really worth to know it! Take look at this case Use regular expression to find/replace substring in NSString

Cutting the length of an NSString without splitting the last word

I'm trying to cut the length of an NSString without splitting the last word with this method:
// cut a string by words
- (NSString* )stringCutByWords:(NSString *)string toLength:(int)length;
{
// search backwards in the string for the beginning of the last word
while ([string characterAtIndex:length] != ' ' && length > 0) {
length--;
}
// if the last word was the first word of the string search for the end of the word
if (length <= 0){
while ([string characterAtIndex:length] != ' ' && length > string.length-1) {
length++;
}
}
// define the range you're interested in
NSRange stringRange = {0, length};
// adjust the range to include dependent chars
stringRange = [string rangeOfComposedCharacterSequencesForRange:stringRange];
// Now you can create the short string
string = [string substringWithRange:stringRange];
return [NSString stringWithFormat:#"%#...",string];
}
now my question is:
Is there a build-in way in objective-c or cocoa-touch which i did not see or else is there a "nicer" way to do this because iam not very happy with this solution.
greetings and thanks for help
C4rmel
My proposal for a Category method
#interface NSString (Cut)
-(NSString *)stringByCuttingExceptLastWordWithLength:(NSUInteger)length;
#end
#implementation NSString (Cut)
-(NSString *)stringByCuttingExceptLastWordWithLength:(NSUInteger)length
{
__block NSMutableString *newString = [NSMutableString string];
NSArray *components = [self componentsSeparatedByString:#" "];
if ([components count] > 0) {
NSString *lastWord = [components objectAtIndex:[components count]-1];
[components enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL *stop) {
if (([obj length]+[newString length] + [lastWord length] + 2) < length) {
[newString appendFormat:#" %#", obj];
} else {
[newString appendString:#"…"];
[newString appendFormat:#" %#", lastWord];
*stop = YES;
}
}];
}
return newString;
}
Usage:
NSString *string = #"Hello World! I am standing over here! Can you see me?";
NSLog(#"%#", [string stringByCuttingExceptLastWordWithLength:25]);
Suggestions:
make it a category method;
use NSCharacterSet and the built-in search methods rather than rolling your own.
So:
/* somewhere public */
#interface NSString (CutByWords)
- (NSString *)stringCutByWordsToMaxLength:(int)length
#end
/* in an implementation file, somewhere */
#implementation NSString (CutByWords)
// cut a string by words
- (NSString *)stringCutByWordsToMaxLength:(int)length
{
NSCharacterSet *whitespaceCharacterSet =
[NSCharacterSet whitespaceCharacterSet];
// to consider: a range check on length here?
NSRange relevantRange = NSMakeRange(0, length);
// find beginning of last word
NSRange lastWordRange =
[self rangeOfCharacterFromSet:whitespaceCharacterSet
options:NSBackwardsSearch
range:relevantRange];
// if the last word was the first word of the string,
// consume the whole string; this looks to be the same
// effect as the original scan forward given that the
// assumption is already made in the scan backwards that
// the string doesn't end on a whitespace; if I'm wrong
// then get [whitespaceCharacterSet invertedSet] and do
// a search forwards
if(lastWordRange.location == NSNotFound)
{
lastWordRange = relevantRange;
}
// adjust the range to include dependent chars
stringRange = [self rangeOfComposedCharacterSequencesForRange:stringRange];
// Now you can create the short string
NSString *string = [self substringWithRange:stringRange];
return [NSString stringWithFormat:#"%#...",string];
}
#end
/* subsequently */
NSString *string = ...whatever...;
NSString *cutString = [string stringCutByWordsToMaxLength:100];

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.

Shortcuts in Objective-C to concatenate NSStrings

Are there any shortcuts to (stringByAppendingString:) string concatenation in Objective-C, or shortcuts for working with NSString in general?
For example, I'd like to make:
NSString *myString = #"This";
NSString *test = [myString stringByAppendingString:#" is just a test"];
something more like:
string myString = "This";
string test = myString + " is just a test";
An option:
[NSString stringWithFormat:#"%#/%#/%#", one, two, three];
Another option:
I'm guessing you're not happy with multiple appends (a+b+c+d), in which case you could do:
NSLog(#"%#", [Util append:one, #" ", two, nil]); // "one two"
NSLog(#"%#", [Util append:three, #"/", two, #"/", one, nil]); // three/two/one
using something like
+ (NSString *) append:(id) first, ...
{
NSString * result = #"";
id eachArg;
va_list alist;
if(first)
{
result = [result stringByAppendingString:first];
va_start(alist, first);
while (eachArg = va_arg(alist, id))
result = [result stringByAppendingString:eachArg];
va_end(alist);
}
return result;
}
Two answers I can think of... neither is particularly as pleasant as just having a concatenation operator.
First, use an NSMutableString, which has an appendString method, removing some of the need for extra temp strings.
Second, use an NSArray to concatenate via the componentsJoinedByString method.
If you have 2 NSString literals, you can also just do this:
NSString *joinedFromLiterals = #"ONE " #"MILLION " #"YEARS " #"DUNGEON!!!";
That's also useful for joining #defines:
#define STRINGA #"Also, I don't know "
#define STRINGB #"where food comes from."
#define JOINED STRINGA STRINGB
Enjoy.
I keep returning to this post and always end up sorting through the answers to find this simple solution that works with as many variables as needed:
[NSString stringWithFormat:#"%#/%#/%#", three, two, one];
For example:
NSString *urlForHttpGet = [NSString stringWithFormat:#"http://example.com/login/username/%#/userid/%i", userName, userId];
Create a method:
- (NSString *)strCat: (NSString *)one: (NSString *)two
{
NSString *myString;
myString = [NSString stringWithFormat:#"%#%#", one , two];
return myString;
}
Then, in whatever function you need it in, set your string or text field or whatever to the return value of this function.
Or, to make a shortcut, convert the NSString into a C++ string and use the '+' there.
Well, as colon is kind of special symbol, but is part of method signature, it is possible to exted the NSString with category to add this non-idiomatic style of string concatenation:
[#"This " : #"feels " : #"almost like " : #"concatenation with operators"];
You can define as many colon separated arguments as you find useful... ;-)
For a good measure, I've also added concat: with variable arguments that takes nil terminated list of strings.
// NSString+Concatenation.h
#import <Foundation/Foundation.h>
#interface NSString (Concatenation)
- (NSString *):(NSString *)a;
- (NSString *):(NSString *)a :(NSString *)b;
- (NSString *):(NSString *)a :(NSString *)b :(NSString *)c;
- (NSString *):(NSString *)a :(NSString *)b :(NSString *)c :(NSString *)d;
- (NSString *)concat:(NSString *)strings, ...;
#end
// NSString+Concatenation.m
#import "NSString+Concatenation.h"
#implementation NSString (Concatenation)
- (NSString *):(NSString *)a { return [self stringByAppendingString:a];}
- (NSString *):(NSString *)a :(NSString *)b { return [[self:a]:b];}
- (NSString *):(NSString *)a :(NSString *)b :(NSString *)c
{ return [[[self:a]:b]:c]; }
- (NSString *):(NSString *)a :(NSString *)b :(NSString *)c :(NSString *)d
{ return [[[[self:a]:b]:c]:d];}
- (NSString *)concat:(NSString *)strings, ...
{
va_list args;
va_start(args, strings);
NSString *s;
NSString *con = [self stringByAppendingString:strings];
while((s = va_arg(args, NSString *)))
con = [con stringByAppendingString:s];
va_end(args);
return con;
}
#end
// NSString+ConcatenationTest.h
#import <SenTestingKit/SenTestingKit.h>
#import "NSString+Concatenation.h"
#interface NSString_ConcatenationTest : SenTestCase
#end
// NSString+ConcatenationTest.m
#import "NSString+ConcatenationTest.h"
#implementation NSString_ConcatenationTest
- (void)testSimpleConcatenation
{
STAssertEqualObjects([#"a":#"b"], #"ab", nil);
STAssertEqualObjects([#"a":#"b":#"c"], #"abc", nil);
STAssertEqualObjects([#"a":#"b":#"c":#"d"], #"abcd", nil);
STAssertEqualObjects([#"a":#"b":#"c":#"d":#"e"], #"abcde", nil);
STAssertEqualObjects([#"this " : #"is " : #"string " : #"concatenation"],
#"this is string concatenation", nil);
}
- (void)testVarArgConcatenation
{
NSString *concatenation = [#"a" concat:#"b", nil];
STAssertEqualObjects(concatenation, #"ab", nil);
concatenation = [concatenation concat:#"c", #"d", concatenation, nil];
STAssertEqualObjects(concatenation, #"abcdab", nil);
}
Use stringByAppendingString: this way:
NSString *string1, *string2, *result;
string1 = #"This is ";
string2 = #"my string.";
result = [result stringByAppendingString:string1];
result = [result stringByAppendingString:string2];
OR
result = [result stringByAppendingString:#"This is "];
result = [result stringByAppendingString:#"my string."];
Macro:
// stringConcat(...)
// A shortcut for concatenating strings (or objects' string representations).
// Input: Any number of non-nil NSObjects.
// Output: All arguments concatenated together into a single NSString.
#define stringConcat(...) \
[#[__VA_ARGS__] componentsJoinedByString:#""]
Test Cases:
- (void)testStringConcat {
NSString *actual;
actual = stringConcat(); //might not make sense, but it's still a valid expression.
STAssertEqualObjects(#"", actual, #"stringConcat");
actual = stringConcat(#"A");
STAssertEqualObjects(#"A", actual, #"stringConcat");
actual = stringConcat(#"A", #"B");
STAssertEqualObjects(#"AB", actual, #"stringConcat");
actual = stringConcat(#"A", #"B", #"C");
STAssertEqualObjects(#"ABC", actual, #"stringConcat");
// works on all NSObjects (not just strings):
actual = stringConcat(#1, #" ", #2, #" ", #3);
STAssertEqualObjects(#"1 2 3", actual, #"stringConcat");
}
Alternate macro: (if you wanted to enforce a minimum number of arguments)
// stringConcat(...)
// A shortcut for concatenating strings (or objects' string representations).
// Input: Two or more non-nil NSObjects.
// Output: All arguments concatenated together into a single NSString.
#define stringConcat(str1, str2, ...) \
[#[ str1, str2, ##__VA_ARGS__] componentsJoinedByString:#""];
When building requests for web services, I find doing something like the following is very easy and makes concatenation readable in Xcode:
NSString* postBody = {
#"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
#"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"
#" <soap:Body>"
#" <WebServiceMethod xmlns=\"\">"
#" <parameter>test</parameter>"
#" </WebServiceMethod>"
#" </soap:Body>"
#"</soap:Envelope>"
};
Shortcut by creating AppendString (AS) macro ...
#define AS(A,B) [(A) stringByAppendingString:(B)]
NSString *myString = #"This";
NSString *test = AS(myString,#" is just a test");
Note:
If using a macro, of course just do it with variadic arguments, see EthanB's answer.
NSString *label1 = #"Process Name: ";
NSString *label2 = #"Process Id: ";
NSString *processName = [[NSProcessInfo processInfo] processName];
NSString *processID = [NSString stringWithFormat:#"%d", [[NSProcessInfo processInfo] processIdentifier]];
NSString *testConcat = [NSString stringWithFormat:#"%# %# %# %#", label1, processName, label2, processID];
Here's a simple way, using the new array literal syntax:
NSString * s = [#[#"one ", #"two ", #"three"] componentsJoinedByString:#""];
^^^^^^^ create array ^^^^^
^^^^^^^ concatenate ^^^^^
NSString *myString = #"This";
NSString *test = [myString stringByAppendingString:#" is just a test"];
After a couple of years now with Objective C I think this is the best way to work with Objective C to achieve what you are trying to achieve.
Start keying in "N" in your Xcode application and it autocompletes to "NSString".
key in "str" and it autocompletes to "stringByAppendingString". So the keystrokes are quite limited.
Once you get the hang of hitting the "#" key and tabbing the process of writing readable code no longer becomes a problem. It is just a matter of adapting.
The only way to make c = [a stringByAppendingString: b] any shorter is to use autocomplete at around the st point. The + operator is part of C, which doesn't know about Objective-C objects.
How about shortening stringByAppendingString and use a #define:
#define and stringByAppendingString
Thus you would use:
NSString* myString = [#"Hello " and #"world"];
Problem is that it only works for two strings, you're required to wrap additional brackets for more appends:
NSString* myString = [[#"Hello" and: #" world"] and: #" again"];
NSString *result=[NSString stringWithFormat:#"%# %#", #"Hello", #"World"];
NSString *label1 = #"Process Name: ";
NSString *label2 = #"Process Id: ";
NSString *processName = [[NSProcessInfo processInfo] processName];
NSString *processID = [NSString stringWithFormat:#"%d", [[NSProcessInfo processInfo] processIdentifier]];
NSString *testConcat = [NSString stringWithFormat:#"%# %# %# %#", label1, processName, label2, processID];
I tried this code. it's worked for me.
NSMutableString * myString=[[NSMutableString alloc]init];
myString=[myString stringByAppendingString:#"first value"];
myString=[myString stringByAppendingString:#"second string"];
Was trying the following in the lldb pane
[NSString stringWithFormat:#"%#/%#/%#", three, two, one];
which errors.
instead use alloc and initWithFormat method:
[[NSString alloc] initWithFormat:#"%#/%#/%#", #"three", #"two", #"one"];
This is for better logging, and logging only - based on dicius excellent multiple argument method. I define a Logger class, and call it like so:
[Logger log: #"foobar ", #" asdads ", theString, nil];
Almost good, except having to end the var args with "nil" but I suppose there's no way around that in Objective-C.
Logger.h
#interface Logger : NSObject {
}
+ (void) log: (id) first, ...;
#end
Logger.m
#implementation Logger
+ (void) log: (id) first, ...
{
// TODO: make efficient; handle arguments other than strings
// thanks to #diciu http://stackoverflow.com/questions/510269/how-do-i-concatenate-strings-in-objective-c
NSString * result = #"";
id eachArg;
va_list alist;
if(first)
{
result = [result stringByAppendingString:first];
va_start(alist, first);
while (eachArg = va_arg(alist, id))
{
result = [result stringByAppendingString:eachArg];
}
va_end(alist);
}
NSLog(#"%#", result);
}
#end
In order to only concat strings, I'd define a Category on NSString and add a static (+) concatenate method to it that looks exactly like the log method above except it returns the string. It's on NSString because it's a string method, and it's static because you want to create a new string from 1-N strings, not call it on any one of the strings that are part of the append.
NSNumber *lat = [NSNumber numberWithDouble:destinationMapView.camera.target.latitude];
NSNumber *lon = [NSNumber numberWithDouble:destinationMapView.camera.target.longitude];
NSString *DesconCatenated = [NSString stringWithFormat:#"%#|%#",lat,lon];
Try stringWithFormat:
NSString *myString = [NSString stringWithFormat:#"%# %# %# %d", "The", "Answer", "Is", 42];
When dealing with strings often I find it easier to make the source file ObjC++, then I can concatenate std::strings using the second method shown in the question.
std::string stdstr = [nsstr UTF8String];
//easier to read and more portable string manipulation goes here...
NSString* nsstr = [NSString stringWithUTF8String:stdstr.c_str()];
My preferred method is this:
NSString *firstString = #"foo";
NSString *secondString = #"bar";
NSString *thirdString = #"baz";
NSString *joinedString = [#[firstString, secondString, thirdString] join];
You can achieve it by adding the join method to NSArray with a category:
#import "NSArray+Join.h"
#implementation NSArray (Join)
-(NSString *)join
{
return [self componentsJoinedByString:#""];
}
#end
#[] it's the short definition for NSArray, I think this is the fastest method to concatenate strings.
If you don't want to use the category, use directly the componentsJoinedByString: method:
NSString *joinedString = [#[firstString, secondString, thirdString] componentsJoinedByString:#""];
You can use NSArray as
NSString *string1=#"This"
NSString *string2=#"is just"
NSString *string3=#"a test"
NSArray *myStrings = [[NSArray alloc] initWithObjects:string1, string2, string3,nil];
NSString *fullLengthString = [myStrings componentsJoinedByString:#" "];
or
you can use
NSString *imageFullName=[NSString stringWithFormat:#"%# %# %#.", string1,string2,string3];
Either of these formats work in XCode7 when I tested:
NSString *sTest1 = {#"This" " and that" " and one more"};
NSString *sTest2 = {
#"This"
" and that"
" and one more"
};
NSLog(#"\n%#\n\n%#",sTest1,sTest2);
For some reason, you only need the # operator character on the first string of the mix.
However, it doesn't work with variable insertion. For that, you can use this extremely simple solution with the exception of using a macro on "cat" instead of "and".
For all Objective C lovers that need this in a UI-Test:
-(void) clearTextField:(XCUIElement*) textField{
NSString* currentInput = (NSString*) textField.value;
NSMutableString* deleteString = [NSMutableString new];
for(int i = 0; i < currentInput.length; ++i) {
[deleteString appendString: [NSString stringWithFormat:#"%c", 8]];
}
[textField typeText:deleteString];
}
listOfCatalogIDs =[#[#"id[]=",listOfCatalogIDs] componentsJoinedByString:#""];
Let's imagine that u don't know how many strings there.
NSMutableArray *arrForStrings = [[NSMutableArray alloc] init];
for (int i=0; i<[allMyStrings count]; i++) {
NSString *str = [allMyStrings objectAtIndex:i];
[arrForStrings addObject:str];
}
NSString *readyString = [[arrForStrings mutableCopy] componentsJoinedByString:#", "];
Inspired by NSMutableString idea from Chris, I make a perfect macro imho.
It supports insert nil elements without any Exceptions.
#import <libextobjc/metamacros.h>
#define STR_CONCAT(...) \
({ \
__auto_type str__ = [NSMutableString string]; \
metamacro_foreach_cxt(never_use_immediately_str_concatify_,, str__, __VA_ARGS__) \
(NSString *)str__.copy; \
})
#define never_use_immediately_str_concatify_(INDEX, CONTEXT, VAR) \
[CONTEXT appendString:VAR ?: #""];
Example:
STR_CONCAT(#"button_bg_", #(count).stringValue, #".png");
// button_bg_2.png
If you like, you can use id type as parameter by using [VAR description] instead of NSString.