क्या NSString stringWithFormat में तर्क स्थिति / सूचकांक निर्दिष्ट करने का कोई तरीका है?


83

C # में सिंटैक्स होता है जो आपको एक स्ट्रिंग प्रारूप विनिर्देशक में तर्क सूचकांक निर्दिष्ट करने की अनुमति देता है, जैसे:

string message = string.Format("Hello, {0}. You are {1} years old. How does it feel to be {1}?", name, age);

आप एक से अधिक बार तर्कों का उपयोग कर सकते हैं और उन दलीलों को भी छोड़ सकते हैं जो उपयोग किए जाने से प्रदान की जाती हैं। एक अन्य प्रश्न में %[index]$[format], उदाहरण के लिए, C / C ++ के समान स्वरूपण का उल्लेख किया गया है %1$i। मैं इस सिंटैक्स का पूरी तरह से सम्मान करने के लिए एनएसएसट्रिंग प्राप्त करने में सक्षम नहीं हूं , क्योंकि यह प्रारूप से तर्कों को छोड़ते समय अच्छा व्यवहार करता है । निम्न अपेक्षा के अनुरूप काम नहीं करता है (EXC_BAD_ACCESS क्योंकि यह ageपैरामीटर को NSObject * के रूप में मान्यता देने का प्रयास करता है ):

int age = 23;
NSString * name = @"Joe";
NSString * message = [NSString stringWithFormat:@"Age: %2$i", name, age];

स्थैतिक तर्कों का सम्मान केवल तभी किया जाता है जब प्रारूप से कोई लापता तर्क न हो (जो कि एक अजीब आवश्यकता लगती है):

NSString * message = [NSString stringWithFormat:@"Age: %2$i; Name: %1$@", name, age];

ये सभी कॉल OS X में ठीक से काम करते हैं:

printf("Age: %2$i", [name UTF8String], age);
printf("Age: %2$i %1$s", [name UTF8String], age);

क्या उद्देश्य-सी / कोको में एनएसएसट्रिंग का उपयोग करके इसे पूरा करने का एक तरीका है? यह स्थानीयकरण के उद्देश्यों के लिए उपयोगी होगा।


बग रिपोर्ट दर्ज करें (और हमें बग # बताएं)।
डर्क थिसिसन

जवाबों:


126

NSString और CFString पुन: प्रयोज्य / स्थिति संबंधी तर्कों का समर्थन करते हैं।

NSString *string = [NSString stringWithFormat: @"Second arg: %2$@, First arg %1$@", @"<1111>", @"<22222>"];
NSLog(@"String = %@", string);

इसके अलावा, Apple में दस्तावेज़ देखें : स्ट्रिंग संसाधन


5
मैंने कुछ स्पष्टीकरण के साथ प्रश्न को अपडेट किया है। ऐसा प्रतीत होता है कि कोको प्रारूप से छोड़ी गई दलीलों का सम्मान नहीं करता है, जो मुझे प्राप्त होने वाले एक्सेस उल्लंघन का एक साइड इफेक्ट था।
जेसन

2
सी काम में जिस तरह से varargs की वजह से छोड़े गए तर्कों का सम्मान करना संभव नहीं है। तर्कों की संख्या या उनके आकार को जानने का कोई मानक तरीका नहीं है। स्ट्रिंग पार्सिंग प्रारूप विनिर्देशकों से जानकारी का हवाला देकर इसे संभालता है, जिसके लिए आवश्यक है कि वास्तव में विनिर्देशक वहां मौजूद हों।
जेन्स एटन जूल

1
मैं समझता हूं कि va_args कैसे काम करता है; हालाँकि, यह उम्मीद के मुताबिक काम करता है: प्रिंटफ ("आयु:% 2 $ i", [नाम UTF8String], आयु); मैंने अन्य प्रिंटफ़ को पुनः क्रमांकित / अनुपस्थित आर्ग के साथ आज़माया है और वे सभी अपेक्षित आउटपुट देते हैं, जबकि NSString नहीं करता है।
जेसन

7
बस मेरे निष्कर्षों को दोहराने के लिए, तब: stringWithFormat:स्थितिगत तर्कों का समर्थन करता है जब तक कि प्रारूप स्ट्रिंग में सभी तर्क निर्दिष्ट किए जाते हैं।
जेसन


1

निम्न कोड इस समस्या में निर्दिष्ट बग को ठीक करता है। यह एक समाधान है और अंतराल को भरने के लिए प्लेसहोल्डर्स का नाम बदल देता है।

+ (id)stringWithFormat:(NSString *)format arguments:(NSArray*) arguments 
{
    NSMutableArray *filteredArguments = [[NSMutableArray alloc] initWithCapacity:arguments.count];
    NSMutableString *correctedFormat = [[NSMutableString alloc ] initWithString:format];
    NSString *placeHolderFormat = @"%%%d$";

    int actualPlaceholderIndex = 1;

    for (int i = 1; i <= arguments.count; ++i) {
        NSString *placeHolder = [[NSString alloc] initWithFormat:placeHolderFormat, i];
        if ([format rangeOfString:placeHolder].location != NSNotFound) {
            [filteredArguments addObject:[arguments objectAtIndex:i - 1]];

            if (actualPlaceholderIndex != i) {
                NSString *replacementPlaceHolder = [[NSString alloc] initWithFormat:placeHolderFormat, actualPlaceholderIndex];
                [correctedFormat replaceAllOccurrencesOfString:placeHolder withString:replacementPlaceHolder];    
                [replacementPlaceHolder release];
            }
            actualPlaceholderIndex++;
        }
        [placeHolder release];
    }

    if (filteredArguments.count == 0) {
        //No numbered arguments found: just copy the original arguments. Mixing of unnumbered and numbered arguments is not supported.
        [filteredArguments setArray:arguments];
    }

    NSString* result;
    if (filteredArguments.count == 0) {
        //Still no arguments: don't use initWithFormat in this case because it will crash: just return the format string
        result = [NSString stringWithString:format];
    } else {
        char *argList = (char *)malloc(sizeof(NSString *) * [filteredArguments count]);
        [filteredArguments getObjects:(id *)argList];
        result = [[[NSString alloc] initWithFormat:correctedFormat arguments:argList] autorelease];
        free(argList);    
    }

    [filteredArguments release];
    [correctedFormat release];

    return result;
}

0

अधिक शोध करने के बाद, ऐसा प्रतीत होता है कि कोकोआ स्थितिक सिंटैक्स का सम्मान करता है printf। इसलिए एक वैकल्पिक पैटर्न होगा:

char msg[512] = {0};
NSString * format = @"Age %2$i, Name: %1$s"; // loaded from resource in practice
sprintf(msg, [format UTF8String], [name UTF8String], age);
NSString * message = [NSString stringWithCString:msg encoding:NSUTF8StringEncoding];

हालाँकि, यह अच्छा होगा यदि एनएसएसटीरिंग पर इसका कार्यान्वयन हो।


1
sprintfकोको का हिस्सा नहीं है, यह सी मानक पुस्तकालय का हिस्सा है, और उस का कार्यान्वयन stringWithFormat:/ है initWithFormat:
पीटर होसी

मेरी पिछली टिप्पणी को स्पष्ट करना: कोको संस्करण है stringWithFormat:/ initWithFormat:। यह एक अलग कार्यान्वयन (वर्तमान में, CFStringCreateWithFormat) से sprintfऔर दोस्तों से है।
पीटर होसी

4
मुझे लगता है कि इस तथ्य पर टिप्पणी करने के लिए बहुत कम उपयोग है कि एमएस को 512 बाइट्स के साथ शुरू करना एक यादृच्छिक ऑब्जेक्ट पर यादृच्छिक चयनकर्ता के रूप में सुरक्षित है, लेकिन वैसे भी। किसी को भी जानकारी नहीं है: फिक्स्ड-साइज़ बफ़र निकाल पाने के कुछ सबसे आसान तरीके हैं। गूगल: बफर ओवरफ्लो
जॉर्ज पेन।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.