题 Objective-C中的快捷方式用于连接NSStrings


有没有快捷方式(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";

1050
2018-02-04 06:26


起源


我只想提出'@ +'作为连接运算符。我将在Objective-C,kthxbai的下一次更新中期待这一点 - powerj1984
@NicolasMiari这不是Objective-C缺乏的唯一功能。还有其他几十个。引自 链接 Jordão发布:“Objective-C是一种原始语言,比较简单。将它与任何现代语言相比较,你很快发现它缺乏。”我同意。 Objective-C(20世纪80年代早期)是C(20世纪70年代早期),增加了一种非常简单且不太类型安全的OOP。没关系,但与Java或C#相比,感觉非常老式。 - jcsahnwaldt
@NicolasMiari:口译语言? C#和Java是编译语言。编译为字节码,然后再次编译为机器码。 - Joren
事情现在改变了:Swift(苹果新语言)更直接 - Pradeep
关于“类型安全”,我认为这是一个风格问题。对于来自C#/ C ++的人来说,拥有任何类型对象的异构数组可能看起来很奇怪,但对于习惯于Objective-C / Cocoa的人来说,它是一种动态和自由的形式;如果您知道自己在做什么,这是一个优势。就像年轻程序员最近抨击C的所有内容一样... - Nicolas Miari


答案:


我能想到的两个答案......既不像只有一个连接运算符那么特别令人愉快。

首先,使用一个 NSMutableString,有一个 appendString 方法,删除一些额外的临时字符串的需要。

第二,使用 NSArray 通过连接来连接 componentsJoinedByString 方法。


580
2018-02-04 06:44



虽然另一个选项有许多赞成票,但我认为如果你在构建时不知道所有的字符串,这是最好的答案。每次附加一个字符串时,都会产生很多开销。使用可变字符串可以消除该问题。 - Eli
+1同意w @Eli。这些通常是最好的解决方案。 NSArray -componentsJoinedByString可以很好地在一行中完成:string = [[NSArray arrayWithObjects:@“This”,“Is”,“A”,“Test”,nil] componentsJoinedByString:@“”]; - Rob Napier
这个答案+1。 [NSMutableString appendString] 比内存更友好 [NSString stringByAppendingStrings]。 - Pierre-David Belanger
@RobNapier:现在使用新的数组文字语法,它甚至更好。 - Amogh Talpallikar
该 [NSString stringWithFormat:@"%@/%@/%@", three, two, one]; 技术似乎最优雅。它应该是选定的答案。 - ekillaby


一个选项:

[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;
}

1064
2018-02-04 07:53



@pablasso同意。 Util方法非常难看。如果你想要这样的东西,它应该作为NSString类别完成,其名称类似于+ stringByAppendingStrings:。即使是像NSStringForAppendedStrings(...)这样的名字的直接函数也会比像Util这样的类中的静态方法更好(名称中包含“Util”的东西可能很少考虑因素)。使用NSMutableString和-appendString可以更好地实现该函数,以避免创建一组无限制的临时自动释放NSStrings。 - Rob Napier
使用大字符串可能会浪费内存。推荐的是更像实际编程语言中的StringBuilder。然后你可以在实际开始追加之前弄清楚需要多少内存。可以重构上述方法来实现此目的。但是,最好创建一个StringBuilder对象,因为这会使用户不必跟踪他们需要组合的所有字符串的列表。 - George
你如何导入Util?这个IDE令人沮丧(没有像eclipse那样建议“import something.Util”,我发现在任何地方都没有提到“Util”。这是一个我应该自己编写的类吗? - Gubatron
stringWithFormat不仅非常优雅,而且功能更强大。你使用它与@“%@%@”连接两个字符串,@“%@%@%@”来连接三个字符串,但你可以在里面放任何多余的字符,打印数字,如果你喜欢重新排序参数等等。格式字符串可以进行本地化,使其强大十倍。字符串连接适用于初学者。 - gnasher729


如果你有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

请享用。


140
2018-03-17 11:59



@CristiBăluţă:)但这只适用于 文字 不是动态创建的NSString实例。 - Johannes Fahrenkrug
你实际上不需要 @在第一个之后的字符串上。 @"I" " really" " enjoy"... - Kevin
您可能希望将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


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

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

例如:

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

67
2017-08-11 06:51





好吧,因为冒号是一种特殊的象征,但是  方法签名的一部分,有可能退出 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);
}

43
2018-03-16 00:41



我在一年前对此进行了投票,因为这不是一个很好的答案。为了应对连接大量字符串,Palimondo的实现需要实现大量非常相似的查找方法,或者多次调用方法,从而导致大量代码基本上只是连接字符串。使用这种方法,您不会获得任何简单的好处 stringWithFormat:。更不用说缺少命名参数,这不仅是非标准的,而且是令人困惑的。 - FreeAsInBeer
原提问者提到了 stringByAppendingString他从来没有说过使用两个以上的论点。我比接受的答案更喜欢这个答案。这很聪明。 - sudo


创造一种方法......

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

然后,无论你需要它做什么功能,设置你的字符串或 textfield 或者该函数的返回值。

或者你可以做什么来制作一个快捷方式是将NSString转换为c ++字符串并在那里使用'+'。

希望这可以帮助!!!!!


35
2017-10-03 22:29





使用这种方式:

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

32
2017-07-26 16:04



你确实意识到你正在建议他想要的东西 不 做,对吧? - SilverSideDown


宏:

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

29
2018-05-31 17:07



有一段时间没有检查过这个问题,但是这些年后我倾向于接受这个作为正确的答案! - typeoneerror
这也可以说比...更好 -[NSString stringByAppendingString:] 对于这个用例 - 如果参数是前者,你会得到一个例外 nil 但如果接收器是,则不是。所以可以想象,你的弦乐送入器中的错误会在默认情况下失败50%,在异常情况下失败50%。同 stringConcat 你可以保证任何例外 nil,列表中的任何位置。这至少是更可预测的。 - Tommy


在构建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>"
};

27
2018-03-16 14:24



对于objective-c noob,你能解释一下这个语法在做什么吗?这会创建一个字符串数组并将它们连接起来吗?对任何文档的引用也会很酷。 - Norman H
@NormanH:这实际上是C语言的一部分。经过一番挖掘,我找到了 这个。它在“字符串连接”阶段下声明:所有相邻的字符串和宽字符串文字是连接在一起的。例如,“String”“concatenation”变为“String concatenation”。 - FreeAsInBeer


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

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

注意:

如果使用宏,当然只需使用可变参数,请参阅EthanB的答案。


25
2017-07-18 05:38



凉!我仍然认为上面的Util是一个更优雅的解决方案;你只能用这个宏附加一个字符串,对吧? - typeoneerror
没错,上面的AS宏会为每行代码添加一个。如果多个附加是常见需求,则可以创建更多宏。例如,一个宏附加两个字符串:<pre> #define A2S(A,B,C)[[(A)stringByAppendingString:(B)] stringByAppendingString:(C)] </ pre>
或者,只需缩短像“#define AS stringByAppendingString”这样的宏所需的输入,然后只需使用“AS”,您通常会键入“stringByAppendingString”,并享受每行代码的多个附加。
这些宏的问题在于它们破坏了Objective-C的一个主要目标,即可读性。目前还不清楚“AS”的作用。以可读性为代价保存一些击键(其中大多数是使用自动完成处理)很少是一个很好的权衡。有一些例外(@“”语法比每次使用+ stringWithUTF8String更具可读性,但目标应该仍然是可读性而不仅仅是简洁性。你写了一次,但你永远调试。 - Rob Napier
嗨罗布 - 我不能同意你的看法。当然,“AS”是一个坏名字。它应该被命名为“CAT”。 - Fattie