Jak przekonwertować std :: string na NSString?


97

Cześć, próbuję przekonwertować standard std::stringna format, NSStringale nie mam szczęścia.

Mogę pomyślnie przekonwertować plik an NSStringna a std::stringza pomocą następującego kodu

NSString *realm = @"Hollywood";
std::string REALM = [realm cStringUsingEncoding:[NSString defaultCStringEncoding]];

Jednak pojawia się błąd czasu kompilacji, gdy próbuję wykonać następujące czynności

NSString *errorMessage = [NSString stringWithCString:REALM encoding:[NSString defaultCStringEncoding]];

Pojawia się błąd

Cannot convert 'std::string' to 'const char*' in argument passing

Czy coś mi umyka?

Z góry dziękuję.


4
To musi być literówka, ale brakuje znaku „@” dla literału ciągu w „NSString * realm =" Hollywood "; ' linia.
Vladimir

Odpowiedzi:


111

Pobierz ciąg c-string z std :: string do konwersji:

NSString *errorMessage = [NSString stringWithCString:REALM.c_str() 
                                   encoding:[NSString defaultCStringEncoding]];

Wydaje się, że nie jest to dobra odpowiedź, ponieważ dokumentacja mówi: / * Kodowanie zależne od użytkownika, którego wartość pochodzi z domyślnego języka użytkownika i potencjalnie innych czynników. Użycie tego kodowania może być czasami potrzebne podczas interpretacji dokumentów użytkownika z nieznanymi kodowaniami, w przypadku braku innych wskazówek. To kodowanie powinno być używane rzadko, jeśli w ogóle. Zauważ, że niektóre potencjalne wartości mogą spowodować nieoczekiwane konwersje kodowania nawet dość prostej treści NSString - na przykład znaki interpunkcyjne z kodowaniem dwukierunkowym. * /
cyrilchampier

30
[NSString stringWithUTF8String: mystring.c_str ()] wydaje się bardziej odpowiednie, ponieważ std :: string jest bardziej prawdopodobne, że pochodzi z twojego własnego kodu, co jest prawdopodobnie w UTF8.
cyrilchampier

Czy wiecie, dlaczego tutaj ( developer.apple.com/documentation/foundation/nsstring/ ) jest napisane „Zwrócony obiekt może różnić się od oryginalnego odbiorcy”? Co to oznacza i skąd możemy wiedzieć, czy jest inaczej?
Julian00,

@cyrilchapier a co, jeśli nasz plik .mm mówi „nie określono konkretnego kodowania”?
Julian00,

53

Po pierwsze, aby to zadziałało, musisz używać Objective-C ++; Najłatwiejszym sposobem upewnienia się, że jest to zmiana nazw wszystkich *.mplików na*.mm

Zdecydowanie najbardziej użytecznym (niezalecanym) ręcznym sposobem umieszczenia C ++ std::stringw pliku NSStringjest:

std::string param; // <-- input
NSString* result = [NSString stringWithUTF8String:param.c_str()];
NSString* alternative = [[NSString alloc] initWithUTF8String:param.c_str()];

To zadziała w większości przypadków - a jeśli nie wykonujesz określonego wykrywania i konwersji kodowania, UTF-8 da ci dobry wynik, ponieważ znaki inne niż łacińskie „po prostu działają”.

Jeśli jednak tworzysz większą aplikację lub nie tylko nad nią pracujesz - prawdopodobnie będziesz potrzebować czegoś, co jest łatwiejsze do zastosowania.

Na podstawie archiwów list dyskusyjnych cocoa-dev

@interface NSString (cppstring_additions)
+(NSString*) stringWithwstring:(const std::wstring&)string;
+(NSString*) stringWithstring:(const std::string&)string;
-(std::wstring) getwstring;
-(std::string) getstring;
@end

@implementation NSString (cppstring_additions)

#if TARGET_RT_BIG_ENDIAN
const NSStringEncoding kEncoding_wchar_t = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingUTF32BE);
#else
const NSStringEncoding kEncoding_wchar_t = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingUTF32LE);
#endif

+(NSString*) stringWithwstring:(const std::wstring&)ws
{
    char* data = (char*)ws.data();
    unsigned size = ws.size() * sizeof(wchar_t);

    NSString* result = [[NSString alloc] initWithBytes:data length:size encoding:kEncoding_wchar_t];
    return result;
}
+(NSString*) stringWithstring:(const std::string&)s
{
    NSString* result = [[NSString alloc] initWithUTF8String:s.c_str()];
    return result;
}

-(std::wstring) getwstring
{
    NSData* asData = [self dataUsingEncoding:kEncoding_wchar_t];
    return std::wstring((wchar_t*)[asData bytes], [asData length] / sizeof(wchar_t));
}
-(std::string) getstring
{
    return [self UTF8String];
}

@end

Dzięki temu na miejscu (i odpowiednio #importzredagowanej) możesz teraz:

NSString* result = [NSString stringWithstring:param];
string convertedBack = [result getstring];

I to samo w przypadku std::wstring, co jest więcej niż przydatne.


1
To jest super i użyłem go w kilku projektach iPhone'a. Jedną z rzeczy, które zauważyłem, było to, że jeśli korzystałem z platformy testów jednostkowych Apple i testowałem bibliotekę, która wykorzystuje te metody, musiałem dołączyć plik zawierający metody konwersji ciągów jako jedno ze „Źródeł kompilacji” w „Fazach kompilacji” dla test jednostkowy. Dziwne.
David

1
Tak, test jednostkowy jest zasadniczo własnym małym programem i musi mieć dostęp do tego samego kodu. Również chwała za pisanie testów ;-)
rvalue

1
Czy wiecie, dlaczego tutaj ( developer.apple.com/documentation/foundation/nsstring/ ) jest napisane „Zwrócony obiekt może różnić się od oryginalnego odbiorcy”? Co to oznacza i skąd możemy wiedzieć, czy jest inaczej?
Julian00,

1
@izzyMachado ten rodzaj języka w dokumentach zwykle oznacza, że ​​zastrzegają sobie „prawo” w ramach kontraktu interfejsu do analizowania, oczyszczania lub kanonizacji ciągu wejściowego. tj. może nie być obiegowy i nadal porównywać, ==ale raczej być „najbliższym” lub „najlepszym” przedstawieniem, jakie mogą wykonać. Odbiornikiem w tym przypadku jest NSStringimplementacja klasy, a zwracana wartość nie jest obiektem Objective-C, więc mogą to również obejmować w jakimś standardowym języku.
rvalue

Czy wiesz, dlaczego to nadal działa, gdy używamy initWithUTF8String, a ciąg zawiera znaki inne niż utf8, w jaki sposób nadal może używać ciągu (jeśli jest to idealny UTF-8) i wydrukować go, gdy stanie się NSString?
Julian00

21
NSString* mystring = [NSString stringWithUTF8String:stdstring.c_str()];

czy to sprawia, że ​​NSString UTF8? lub jakie kodowanie będzie NSString?
Julian00

14

Apple ma teraz nowy sposób, w jaki chcą, abyś dokonał tej konwersji. W XCode7 użyłem opcji Edycja> Konwertuj> Na nowoczesną składnię celu C ..., aby się tego dowiedzieć. Używa skróconego symbolu @.

std::string sCPPString = "Hello World!";
NSString *sAppleString = @(sCPPString.c_str());

3

Odkryłem również, że:

NSString *nsString = [NSString stringWithFormat:@"%s",standardString];

Działa jak mistrz.


3
To dość niebezpieczne i nie ma gwarancji, że zadziała. standardString, jeśli std :: string, jest obiektem C ++. Obiekty C ++ nie są bezpieczne do przekazywania do funkcji wariadycznych (szablony wariadyczne rozwiązują ten problem w C ++ 11). Jeśli to działa, to fuks i prawie każdy kompilator przynajmniej ostrzeże Cię przed tym (jeśli nie jest to błąd).
Vitali

3

Oto fragment kodu / przykład:

string str_simple = "HELLO WORLD";

//string to NSString
NSString *stringinObjC = [NSString stringWithCString:str_simple.c_str()
                                encoding:[NSString defaultCStringEncoding]];            
NSLog(stringinObjC);
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.