Objective-C中连接NSString的快捷方式


1129

stringByAppendingString:在Objective-C中,是否有用于()字符串连接的快捷方式,或者NSString是通常使用的快捷方式?

例如,我想做:

NSString *myString = @"This";
NSString *test = [myString stringByAppendingString:@" is just a test"];

更像是:

string myString = "This";
string test = myString + " is just a test";

4
我只想提出“ @ +”作为串联运算符。我希望在下一次对Objective-C(kthxbai)的更新中
powerj1984

44
@NicolasMiari这不是Objective-C唯一缺少的功能。还有几十个。乔丹(Jordão)发布的链接中写道:“简单地说,Objective-C是一种原始语言。将其与任何现代语言进行比较,您很快就会发现它缺乏。” 我同意。Objective-C(1980年代初)是C(1970年代初),其中增加了一种非常简单且不是非常类型安全的OOP。可以,但是与Java或C#相比,它感觉很过时。
jcsahnwaldt说GoFundMonica

5
@NicolasMiari:口译语言?C#和Java是编译语言。编译为字节码,然后再次编译为机器码。
乔伦(Joren)2013年

3
现在情况发生改变:斯威夫特(苹果新的语言)更直截了当
普拉迪普

6
关于“类型安全”,我认为这是风格问题。对于来自C#/ C ++的人来说,拥有各种类型的对象的异类数组可能看起来很奇怪,但是对于习惯了Objective-C / Cocoa的人来说,这是一种活力和自由的形式。只要您知道自己在做什么,这是一个优势。
如今

Answers:


616

我能想到的两个答案...哪一个都不像拥有串联运算符那样令人愉悦。

首先,使用NSMutableString具有appendString方法的,从而消除了一些额外的临时字符串。

其次,使用NSArray通过componentsJoinedByString方法串联。


34
尽管另一个选择有很多反对意见,但我认为如果您不了解构建过程中的所有字符串,这是最佳答案。每次附加字符串时,都会造成大量开销。使用可变字符串可以解决该问题。
Eli

22
+1同意@Eli。这些通常是最好的解决方案。NSArray -componentsJoinedByString可以很好地在一行中完成:string = [[NSArray arrayWithObjects:@“ This”,“ Is”,“ A”,“ Test”,nil] componentsJoinedByString:@“”];
罗布·纳皮尔

4
为此答案+1。[NSMutableString appendString]比记忆友好[NSString stringByAppendingStrings]
Pierre-David Belanger

2
@RobNapier:现在有了新的数组文字语法,它甚至更好。
Amogh Talpallikar

27
[NSString stringWithFormat:@"%@/%@/%@", three, two, one];技术似乎是最优雅的。它应该是选定的答案。
ekillaby 2014年

1129

一个选项:

[NSString stringWithFormat:@"%@/%@/%@", one, two, three];

另外一个选项:

我猜您对多个追加(a + b + c + d)不满意,在这种情况下,您可以这样做:

NSLog(@"%@", [Util append:one, @" ", two, nil]); // "one two"
NSLog(@"%@", [Util append:three, @"/", two, @"/", one, nil]); // three/two/one

使用类似

+ (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;
}

8
@pablasso同意。Util方法非常难看。如果您想要这样的事情,则应将其作为NSString类别来完成,其名称应类似于+ stringByAppendingStrings:。即使是名称简单的函数,如NSStringForAppendedStrings(...),也比静态方法在Util之类的方法中要好(名称中带有“ Util”的任何东西都可能考虑得不好)。还可以使用NSMutableString和-appendString更好地实现该函数,以避免创建无限制的一组临时自动释放的NSString。
罗布·纳皮尔

1
使用大字符串会浪费内存。推荐使用类似于RealBuild语言的StringBuilder。然后,您可以在实际开始追加之前弄清楚需要多少内存。可以重构以上方法来做到这一点。但是,最好创建一个StringBuilder对象,因为这样可以使它的用户不必跟踪他们需要组合的所有字符串的列表。
乔治,

您如何导入实用程序?这个IDE令人沮丧(在eclipse上没有建议“导入something.Util”,在任何地方我都没有提到“ Util”。这是我应该自己编写的类吗?
Gubatron 2014年

stringWithFormat不仅非常优雅,而且功能更强大。您可以将其与@“%@%@”并置两个字符串,将@“%@%@%@”并置三个字符串,但是您可以在其中放入任何多余的字符,打印数字,根据需要对参数进行重新排序等等。 。格式字符串可以本地化,使其功能强大十倍。字符串连接适用于初学者。
gnasher729

150

如果您有2个NSString 文字,也可以执行以下操作:

NSString *joinedFromLiterals = @"ONE " @"MILLION " @"YEARS " @"DUNGEON!!!";

这对于加入#defines也很有用:

#define STRINGA @"Also, I don't know "
#define STRINGB @"where food comes from."
#define JOINED STRINGA STRINGB

请享用。


13
@ CristiBăluță :)但这仅适用于文字,不适用于动态创建的NSString实例。
Johannes Fahrenkrug

9
实际上,您不需要在@第一个之后的字符串上使用。@"I" " really" " enjoy"...
凯文

您可能应该将STRINGA和STRINGB放在括号内,否则在解析宏时可能会得到奇怪的结果。#define JOINED(STRINGA STRINGB)
digory doo

@JohannesFahrenkrug那么为什么这NSString* const SQL_CREATE_TABLE_str = @"CREATE TABLE IF NOT EXISTS " TABLE_NAME @" (...);";不起作用?我遇到了Expected '@' in program错误:(
Vagif

@Vagif是如何TABLE_NAME定义的?
Johannes Fahrenkrug

75

我继续回到这篇文章,总是最终对答案进行排序,以找到这个简单的解决方案,该解决方案可以根据需要使用多个变量:

[NSString stringWithFormat:@"%@/%@/%@", three, two, one];

例如:

NSString *urlForHttpGet = [NSString stringWithFormat:@"http://example.com/login/username/%@/userid/%i", userName, userId];

48

创建一个方法:

- (NSString *)strCat: (NSString *)one: (NSString *)two
{
    NSString *myString;
    myString = [NSString stringWithFormat:@"%@%@", one , two];
    return myString;
}

然后,在需要的任何函数中,将字符串或文本字段设置为该函数的返回值。

或者,要创建快捷方式,请将NSString转换为C ++字符串,然后在其中使用“ +”。


这是最简单的解决方案。
GeneCode

44

那么,结肠癌是一种特殊的符号,但是方法签名的一部分,有可能加长的NSString类别为添加这个非惯用的字符串连接的风格:

[@"This " : @"feels " : @"almost like " : @"concatenation with operators"];

您可以定义尽可能多的用冒号分隔的参数... ;-)

作为一项很好的措施,我还添加了concat:带有nil终止字符串列表的可变参数。

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

20
我一年前对此表示反对,因为这不是一个很好的答案。为了应对串联的大量字符串,Palimondo的实现需要要么实现大量看起来很相似的方法,要么多次调用这些方法,从而导致产生大量的代码,这些代码实际上只是串联字符串。使用这种方法,您不会从simple获得任何好处stringWithFormat:。更不用说缺少命名参数了,这不仅是非标准的,而且令人困惑。
FreeAsInBeer 2013年

2
最初的询问者提到了stringByAppendingString,而他从来没有说过要使用两个以上的论点。我比接受的答案更喜欢这个答案。非常聪明。
sudo 2014年

32

使用stringByAppendingString:这种方式:

NSString *string1, *string2, *result;

string1 = @"This is ";
string2 = @"my string.";

result = [result stringByAppendingString:string1];
result = [result stringByAppendingString:string2];

要么

result = [result stringByAppendingString:@"This is "];
result = [result stringByAppendingString:@"my string."];

34
你一定要明白,你是在暗示他想要的确切的事情没有做,对不对?
SilverSideDown 2012年

这么多的泄漏!
RamGrg

30

巨集:

// 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:@""]

测试用例:

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

备用宏:(如果您想强制使用最少数量的参数)

// 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:@""];

2
一段时间没有检查这个问题,但是这些年来,我倾向于将其作为正确的答案!
typeoneerror

1
可以说-[NSString stringByAppendingString:],这比本用例具有更好的行为-如果参数为,则前者会出现异常,nil但如果接收者为,则不会。因此,可以想象的是,在字符串供稿器无提示失败时,错误的几率为50%,在异常情况下的几率为50%。通过这种方式,stringConcat您可以确保nil列表中任何地方的异常。至少更可预测。
汤米

27

在构建对Web服务的请求时,我发现执行以下操作非常容易,并且可以使串联在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>"
};

对于Objective-C新手,您可以解释这种语法的作用吗?这是否会创建字符串数组并以某种方式将它们连接起来?对任何文档的引用也很酷。
诺曼H

2
@NormanH:这实际上是C语言的一部分。经过一番挖掘,我找到了这个。它在“字符串串联”阶段下声明:所有相邻的字符串和宽字符串文字均被串联。例如,“字符串”“连接”变为“字符串连接”。
FreeAsInBeer 2012年

27

通过创建AppendString(AS)宏的快捷方式...

#define AS(A,B)[(A)stringByAppendingString:(B)]
NSString * myString = @“此”; NSString * test = AS(myString,@“只是一个测试”);

注意:

如果使用宏,则只需使用可变参数即可,请参见EthanB的答案。


凉!我仍然认为上面的实用程序是一种更为优雅的解决方案。您只能在此宏后面附加一个字符串,对吗?
typeoneerror

1
的确,上面的AS宏每行代码执行一次追加。如果通常需要多个追加,则可以创建更多的宏。例如,一个用于追加两个字符串的宏:<pre> #define A2S(A,B,C)[[(A)stringByAppendingString:(B)] stringByAppendingString:(C)] </ pre>

2
或者,只需使用“ #define AS stringByAppendingString”之类的宏来缩短所需的键入,然后仅使用“ AS”即可(通常会键入“ stringByAppendingString”),并享受每行代码的多次追加。

15
这些宏的问题在于它们破坏了Objective-C的主要目标之一,即可读性。目前还不清楚“ AS”的作用。很少以牺牲可读性为代价来节省一些击键(大多数击键是通过自动完成来完成的)。有例外(@“”语法比每次必须使用+ stringWithUTF8String:更具可读性),但是目标仍然应该是可读性,而不是简洁。您只编写一次,但是却永远调试。
罗布·纳皮尔

嗨,罗布(Rob)-我不​​能同意你的看法。当然,“ AS”是一个坏名字。应该将其命名为“ CAT”。
Fattie 2015年

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

11

这是使用新数组文字语法的一种简单方法:

NSString * s = [@[@"one ", @"two ", @"three"] componentsJoinedByString:@""];
                  ^^^^^^^ create array ^^^^^
                                               ^^^^^^^ concatenate ^^^^^

9
NSString *myString = @"This";
NSString *test = [myString stringByAppendingString:@" is just a test"];

在使用Objective CI几年之后,认为这是与Objective C一起实现您想要达到的目标的最佳方法。

在您的Xcode应用程序中开始键入“ N”,它会自动完成为“ NSString”。键入“ str”,它将自动完成为“ stringByAppendingString”。因此,击键非常有限。

一旦您掌握了敲击“ @”键并在编写可读代码的过程中添加标签的麻烦,则不再成为问题。这只是适应问题。


你一定要明白,你是在暗示他想要的确切的事情没有做,对不对?
不是用户的用户

8

c = [a stringByAppendingString: b]缩短时间的唯一方法是在此时使用自动完成功能st。该+运营商是C,不知道Objective-C对象的一部分。


你一定要明白,你是在暗示他想要的确切的事情没有做,对不对?至少#define可以使用a来缩短它。
不是用户的用户

8

如何缩短stringByAppendingString和使用#define

#define and stringByAppendingString

因此,您将使用:

NSString* myString = [@"Hello " and @"world"];

问题在于,它仅适用于两个字符串,您需要包装更多的括号以进行更多追加:

NSString* myString = [[@"Hello" and: @" world"] and: @" again"];

XCode7不再允许您使用此选项-说“和”是保留字。但是,可以使用“ cat”代替。我做到了,您的解决方案运行完美,非常简单。
Volomike '16

8
NSString *result=[NSString stringWithFormat:@"%@ %@", @"Hello", @"World"];

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

6

我尝试了这段代码。对我有用。

NSMutableString * myString=[[NSMutableString alloc]init];
myString=[myString stringByAppendingString:@"first value"];
myString=[myString stringByAppendingString:@"second string"];

2
这是有史以来对NSMutableString的最严重的滥用。NSMutableString的全部要点是,您不需要创建自动发布的字符串的方法,但是可以修改字符串本身。
gnasher729

同意。至少appendString:在使用时使用NSMutableString
不是用户的用户

6

lldb窗格中尝试以下内容

[NSString stringWithFormat:@"%@/%@/%@", three, two, one];

哪些错误。

而是使用alloc和initWithFormatmethod:

[[NSString alloc] initWithFormat:@"%@/%@/%@", @"three", @"two", @"one"];

1
...希望我有足够的声誉来发表评论,但希望这对其他人有帮助。
Anthony De Souza 2014年

4

这是用于更好的日志记录,并且仅用于日志记录-基于dicius出色的多参数方法。我定义一个Logger类,并按如下方式调用它:

[Logger log: @"foobar ", @" asdads ", theString, nil];

几乎好,除了必须以“ nil”结尾var args,但我想在Objective-C中无法解决这个问题。

记录器

@interface Logger : NSObject {
}
+ (void) log: (id) first, ...;
@end

记录器

@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 

为了只连接字符串,我将在NSString上定义一个Category,并向其添加一个静态(+)串联方法,该方法与上面的log方法完全一样,只不过它返回字符串。它位于NSString上,因为它是一个字符串方法,它是静态的,因为您想从1-N个字符串创建一个新字符串,而不是对作为追加一部分的任何一个字符串调用它。


4
NSNumber *lat = [NSNumber numberWithDouble:destinationMapView.camera.target.latitude];
NSNumber *lon = [NSNumber numberWithDouble:destinationMapView.camera.target.longitude];
NSString *DesconCatenated = [NSString stringWithFormat:@"%@|%@",lat,lon];

3

尝试stringWithFormat:

NSString *myString = [NSString stringWithFormat:@"%@ %@ %@ %d", "The", "Answer", "Is", 42];

为什么会有2个降票?是因为已经在另一个答案中提到了这一点吗?
Reimius 2012年

3

当经常处理字符串时,我发现使源文件ObjC ++更容易,然后可以使用问题中显示的第二种方法来连接std :: strings。

std::string stdstr = [nsstr UTF8String];

//easier to read and more portable string manipulation goes here...

NSString* nsstr = [NSString stringWithUTF8String:stdstr.c_str()];

3

我的首选方法是这样的:

NSString *firstString = @"foo";
NSString *secondString = @"bar";
NSString *thirdString = @"baz";

NSString *joinedString = [@[firstString, secondString, thirdString] join];

您可以通过将join方法添加到带有以下类别的NSArray来实现:

#import "NSArray+Join.h"
@implementation NSArray (Join)
-(NSString *)join
{
    return [self componentsJoinedByString:@""];
}
@end

@[]这是的简短定义NSArray,我认为这是连接字符串的最快方法。

如果您不想使用类别,请直接使用componentsJoinedByString:方法:

NSString *joinedString = [@[firstString, secondString, thirdString] componentsJoinedByString:@""];

3

您可以使用NSArray作为

NSString *string1=@"This"

NSString *string2=@"is just"

NSString *string3=@"a test"  

NSArray *myStrings = [[NSArray alloc] initWithObjects:string1, string2, string3,nil];

NSString *fullLengthString = [myStrings componentsJoinedByString:@" "];

要么

您可以使用

NSString *imageFullName=[NSString stringWithFormat:@"%@ %@ %@.", string1,string2,string3];

1

测试时,以下两种格式均可在XCode7中使用:

NSString *sTest1 = {@"This" " and that" " and one more"};
NSString *sTest2 = {
  @"This"
  " and that"
  " and one more"
};

NSLog(@"\n%@\n\n%@",sTest1,sTest2);

由于某些原因,您只需要在混合的第一个字符串上使用@运算符。

但是,它不适用于变量插入。为此,除了在“ cat”上使用宏而不是“ and”之外,您可以使用此极其简单的解决方案


如何做到这一点?例如:sTest3 = sTest1 + sTest2;

@ user285594这就是问题的重点:Objective-C中不允许使用该语法。查看其他答案。
不是用户的用户

1

对于在UI测试中需要此功能的所有Objective C爱好者:

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

0
listOfCatalogIDs =[@[@"id[]=",listOfCatalogIDs] componentsJoinedByString:@""];

0

假设您不知道那里有多少个字符串。

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:@", "];
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.