Szukaj…


Wprowadzenie

Ciągi to obiekty reprezentujące sekwencje znaków. Średnia string klasa zapewnia prostą, bezpieczną i wszechstronną alternatywę dla korzystania wyraźne tablice char s gdy mamy do czynienia z tekstem i innych ciągów znaków. Klasa string C ++ jest częścią std przestrzeni nazw i została znormalizowana w 1998 roku.

Składnia

  • // Deklaracja pustego ciągu

    std :: string s;

  • // Konstruowanie z const char * (ciąg c)

    std :: string s („Hello”);

    std :: string s = "Hello";

  • // Konstruowanie za pomocą konstruktora kopii

    std :: string s1 („Hello”);

    std :: string s2 (s1);

  • // Konstruowanie z podciągów

    std :: string s1 („Hello”);

    std :: string s2 (s1, 0, 4); // Skopiuj 4 znaki z pozycji 0 s1 do s2

  • // Konstruowanie z bufora znaków

    std :: string s1 („Hello World”);
    std :: string s2 (s1, 5); // Skopiuj 5 pierwszych znaków s1 do s2

  • // Konstruuj za pomocą konstruktora wypełnienia (tylko char)

    std :: string s (5, 'a'); // s zawiera aaaaa

  • // Konstruuj za pomocą konstruktora zasięgu i iteratora

    std :: string s1 („Hello World”);

    std :: string s2 (s1.begin (), s1.begin () + 5); // Skopiuj 5 pierwszych znaków s1 do s2

Uwagi

Przed użyciem std::string należy dołączyć string nagłówka, ponieważ zawiera on funkcje / operatory / przeciążenia, których nie zawierają inne nagłówki (na przykład iostream ).


Używanie konstruktora const char * z nullptr prowadzi do niezdefiniowanego zachowania.

std::string oops(nullptr);
std::cout << oops << "\n";

Metoda at zgłasza wyjątek std::out_of_range jeśli index >= size() .

Zachowanie operator[] jest nieco bardziej skomplikowane, we wszystkich przypadkach ma niezdefiniowane zachowanie, jeśli index > size() , ale gdy index == size() :

C ++ 11
  1. W przypadku ciągów innych niż zachowanie zachowanie jest niezdefiniowane ;
  2. W ciąg znaków CharT() jest odwołanie do znaku o wartości CharT() (znak zerowy ).
C ++ 11
  1. CharT() jest odwołanie do znaku o wartości CharT() (znak zerowy ).
  2. Modyfikowanie tego odwołania jest niezdefiniowanym zachowaniem .

Ponieważ w C ++ 14 zamiast "foo" zaleca się stosowanie "foo"s , ponieważ s to zdefiniowany przez użytkownika przyrostek literału , który konwertuje const char* "foo" na std::string "foo" .

Uwaga: musisz użyć przestrzeni nazw std::string_literals lub std::literals aby uzyskać literały s .

Rozdzielać

Użyj std::string::substr aby podzielić ciąg. Istnieją dwa warianty tej funkcji składowej.

Pierwszy zajmuje pozycję początkową, od której powinien zacząć się zwracany podciąg. Pozycja początkowa musi być ważna w zakresie (0, str.length()] :

std::string str = "Hello foo, bar and world!";
std::string newstr = str.substr(11); // "bar and world!"

Drugi zajmuje pozycję początkową i całkowitą długość nowego podciągu. Bez względu na długość podciąg nigdy nie przekroczy końca łańcucha źródłowego:

std::string str = "Hello foo, bar and world!";
std::string newstr = str.substr(15, 3); // "and"

Zauważ, że możesz także wywołać substr bez żadnych argumentów, w tym przypadku zwracana jest dokładna kopia ciągu

std::string str = "Hello foo, bar and world!";
std::string newstr = str.substr(); // "Hello foo, bar and world!"

Wymiana ciągów

Zastąp według pozycji

Aby zamienić część std::string , możesz użyć metody replace from std::string .

replace ma wiele przydatnych przeciążeń:

//Define string
std::string str = "Hello foo, bar and world!";
std::string alternate = "Hello foobar";

//1)
str.replace(6, 3, "bar"); //"Hello bar, bar and world!"

//2)
str.replace(str.begin() + 6, str.end(), "nobody!"); //"Hello nobody!"

//3)
str.replace(19, 5, alternate, 6, 6); //"Hello foo, bar and foobar!"
C ++ 14
//4)
str.replace(19, 5, alternate, 6); //"Hello foo, bar and foobar!"
//5)
str.replace(str.begin(), str.begin() + 5, str.begin() + 6, str.begin() + 9);
//"foo foo, bar and world!"

//6)
str.replace(0, 5, 3, 'z'); //"zzz foo, bar and world!"

//7)
str.replace(str.begin() + 6, str.begin() + 9, 3, 'x'); //"Hello xxx, bar and world!"
C ++ 11
//8)
str.replace(str.begin(), str.begin() + 5, { 'x', 'y', 'z' }); //"xyz foo, bar and world!"

Zamień wystąpienia ciągu na inny

Wymienić tylko pierwsze wystąpienie replace z with w str :

std::string replaceString(std::string str,
                          const std::string& replace,
                          const std::string& with){
    std::size_t pos = str.find(replace);
    if (pos != std::string::npos)
        str.replace(pos, replace.length(), with);
    return str;
}

Zastąpić wszystkie wystąpienia replace z with w str :

std::string replaceStringAll(std::string str,
                             const std::string& replace,
                             const std::string& with) {
    if(!replace.empty()) {
        std::size_t pos = 0;
        while ((pos = str.find(replace, pos)) != std::string::npos) {
            str.replace(pos, replace.length(), with);
            pos += with.length();
        }
    }
    return str;
}

Powiązanie

Możesz połączyć std::string s przy użyciu przeciążonych operatorów + i += . Za pomocą operatora + :

std::string hello = "Hello";
std::string world = "world";
std::string helloworld = hello + world; // "Helloworld"

Za pomocą operatora += :

std::string hello = "Hello";
std::string world = "world";
hello += world; // "Helloworld"

Możesz także dołączyć ciągi C, w tym literały ciągów:

std::string hello = "Hello";
std::string world = "world";
const char *comma = ", ";
std::string newhelloworld = hello + comma + world + "!"; // "Hello, world!"

Możesz także użyć push_back() aby wypchnąć poszczególne char :

std::string s = "a, b, ";
s.push_back('c'); // "a, b, c"

Istnieje również append() , który jest podobny do += :

std::string app = "test and ";
app.append("test"); // "test and test"

Dostęp do postaci

Istnieje kilka sposobów wyodrębnienia znaków ze std::string i każdy z nich jest nieco inny.

std::string str("Hello world!");

operator [] (n)

Zwraca odniesienie do znaku o indeksie n.

std::string::operator[] nie jest sprawdzany pod kątem granic i nie zgłasza wyjątku. Osoba dzwoniąca jest odpowiedzialna za zapewnienie, że indeks mieści się w zakresie ciągu:

char c = str[6]; // 'w'

w (n)

Zwraca odniesienie do znaku o indeksie n.

std::string::at jest zaznaczone, i wyrzuci std::out_of_range jeśli indeks nie znajduje się w zakresie ciągu:

char c = str.at(7); // 'o'
C ++ 11

Uwaga: oba te przykłady spowodują niezdefiniowane zachowanie, jeśli ciąg będzie pusty.


z przodu()

Zwraca odniesienie do pierwszego znaku:

char c = str.front(); // 'H'

plecy()

Zwraca odniesienie do ostatniego znaku:

char c = str.back(); // '!'

Tokenize

Wymienione od najtańszego do najdroższego w czasie wykonywania:

  1. str::strtok to najtańsza standardowa metoda tokenizacji, pozwala także modyfikować separator między tokenami, ale wiąże się z 3 trudnościami ze współczesnym C ++:

    • std::strtok nie może być używany na wielu strings jednocześnie (choć niektóre implementacje obsługują to, na przykład: strtok_s )
    • Z tego samego powodu nie można używać std::strtok jednocześnie w wielu wątkach (może to być jednak zdefiniowana implementacja, na przykład: implementacja Visual Studio jest bezpieczna dla wątków )
    • Wywołanie std::strtok modyfikuje std::string którym działa, więc nie można go używać w const string s, const char* s ani ciągach literalnych, aby tokenizować dowolne z nich za pomocą std::strtok lub operować na std::string którego zawartość musi zostać zachowana, dane wejściowe musiałyby zostać skopiowane, a następnie można by operować na kopii

    Zasadniczo każda z tych opcji będzie ukryta w koszcie alokacji tokenów, ale jeśli wymagany jest najtańszy algorytm, a trudności std::strtok nie są nadmierne, rozważ rozwiązanie ręczne .

// String to tokenize
std::string str{ "The quick brown fox" };
// Vector to store tokens
vector<std::string> tokens;

for (auto i = strtok(&str[0], " "); i != NULL; i = strtok(NULL, " "))
    tokens.push_back(i);

Przykład na żywo

  1. std::istream_iterator używa iteracyjnie operatora ekstrakcji strumienia. Jeśli wejściowy std::string jest ograniczony białymi spacjami, jest w stanie rozwinąć opcję std::strtok , eliminując jego trudności, umożliwiając wbudowane tokenizowanie, wspierając w ten sposób generowanie stałego const vector<string> i dodając obsługę wielu ograniczanie białych znaków:
// String to tokenize
const std::string str("The  quick \tbrown \nfox");
std::istringstream is(str);
// Vector to store tokens
const std::vector<std::string> tokens = std::vector<std::string>(
                                        std::istream_iterator<std::string>(is),
                                        std::istream_iterator<std::string>());

Przykład na żywo

  1. std::regex_token_iterator używa std::regex do iteracyjnego tokenizacji. Zapewnia bardziej elastyczną definicję separatora. Na przykład nieprzedzielone przecinki i białe znaki:
C ++ 11
// String to tokenize
const std::string str{ "The ,qu\\,ick ,\tbrown, fox" };
const std::regex re{ "\\s*((?:[^\\\\,]|\\\\.)*?)\\s*(?:,|$)" };
// Vector to store tokens
const std::vector<std::string> tokens{ 
    std::sregex_token_iterator(str.begin(), str.end(), re, 1), 
    std::sregex_token_iterator() 
};

Przykład na żywo

Więcej informacji regex_token_iterator przykładzie regex_token_iterator .

Konwersja na (const) char *

Aby uzyskać dostęp const char* do danych std::string , możesz użyć funkcji członka c_str() łańcucha. Należy pamiętać, że wskaźnik jest poprawny tylko tak długo, jak długo obiekt std::string znajduje się w zakresie i pozostaje niezmieniony, co oznacza, że na obiekcie można wywoływać tylko metody const .

C ++ 17

Funkcji składowej data() można użyć do uzyskania modyfikowalnego char* , który może służyć do manipulowania danymi obiektu std::string .

C ++ 11

Zmodyfikowalny char* można również uzyskać, biorąc adres pierwszego znaku: &s[0] . W ramach C ++ 11 gwarantuje to uzyskanie dobrze uformowanego łańcucha zakończonego znakiem null. Zauważ, że &s[0] jest dobrze sformułowany, nawet jeśli s jest pusty, podczas gdy &s.front() jest niezdefiniowany, jeśli s jest pusty.

C ++ 11
std::string str("This is a string.");
const char* cstr = str.c_str(); // cstr points to: "This is a string.\0"
const char* data = str.data();  // data points to: "This is a string.\0"
std::string str("This is a string.");

// Copy the contents of str to untie lifetime from the std::string object
std::unique_ptr<char []> cstr = std::make_unique<char[]>(str.size() + 1);

// Alternative to the line above (no exception safety):
// char* cstr_unsafe = new char[str.size() + 1];

std::copy(str.data(), str.data() + str.size(), cstr);
cstr[str.size()] = '\0'; // A null-terminator needs to be added

// delete[] cstr_unsafe;
std::cout << cstr.get();

Znajdowanie postaci w ciągu

Aby znaleźć znak lub inny ciąg, możesz użyć std::string::find . Zwraca pozycję pierwszego znaku pierwszego meczu. Jeśli nie znaleziono żadnych dopasowań, funkcja zwraca std::string::npos

std::string str = "Curiosity killed the cat";
auto it = str.find("cat");

if (it != std::string::npos)
    std::cout << "Found at position: " << it << '\n';
else
    std::cout << "Not found!\n";

Znaleziony na pozycji: 21


Możliwości wyszukiwania są dalej rozszerzane o następujące funkcje:

find_first_of     // Find first occurrence of characters 
find_first_not_of // Find first absence of characters 
find_last_of      // Find last occurrence of characters 
find_last_not_of  // Find last absence of characters 

Funkcje te pozwalają wyszukiwać znaki z końca łańcucha, a także znajdować wielkość ujemną (tj. Znaki, które nie są w łańcuchu). Oto przykład:

std::string str = "dog dog cat cat";
std::cout << "Found at position: " << str.find_last_of("gzx") << '\n';

Znaleziono w pozycji: 6

Uwaga: należy pamiętać, że powyższe funkcje nie wyszukują podciągów, lecz raczej znaki zawarte w wyszukiwanym ciągu. W tym przypadku ostatnie wystąpienie 'g' znaleziono na pozycji 6 (pozostałych znaków nie znaleziono).

Przycinanie znaków na początku / na końcu

Ten przykład wymaga nagłówków <algorithm> , <locale> i <utility> .

C ++ 11

Przycinanie sekwencji lub łańcucha oznacza usunięcie wszystkich wiodących i końcowych elementów (lub znaków) pasujących do określonego predykatu. Najpierw przycinamy elementy końcowe, ponieważ nie wymaga to przenoszenia żadnych elementów, a następnie przycinamy elementy wiodące. Zauważ, że poniższe uogólnienia działają dla wszystkich typów std::basic_string (np. std::wstring std::string i std::wstring ), a przypadkowo także dla kontenerów sekwencji (np. std::vector i std::list ).

template <typename Sequence, // any basic_string, vector, list etc.
          typename Pred>     // a predicate on the element (character) type
Sequence& trim(Sequence& seq, Pred pred) {
    return trim_start(trim_end(seq, pred), pred);
}

Przycinanie końcowych elementów polega na znalezieniu ostatniego elementu, który nie pasuje do predykatu, i stamtąd:

template <typename Sequence, typename Pred>
Sequence& trim_end(Sequence& seq, Pred pred) {
    auto last = std::find_if_not(seq.rbegin(),
                                 seq.rend(),
                                 pred);
    seq.erase(last.base(), seq.end());
    return seq;
}

Przycinanie elementów wiodących polega na znalezieniu pierwszego elementu, który nie pasuje do predykatu i skasowaniu do tego miejsca:

template <typename Sequence, typename Pred>
Sequence& trim_start(Sequence& seq, Pred pred) {
    auto first = std::find_if_not(seq.begin(),
                                  seq.end(),
                                  pred);
    seq.erase(seq.begin(), first);
    return seq;
}

Aby wyspecjalizować powyższe do przycinania białych znaków w std::string , możemy użyć funkcji std::isspace() jako predykatu:

std::string& trim(std::string& str, const std::locale& loc = std::locale()) {
    return trim(str, [&loc](const char c){ return std::isspace(c, loc); });
}

std::string& trim_start(std::string& str, const std::locale& loc = std::locale()) {
    return trim_start(str, [&loc](const char c){ return std::isspace(c, loc); });
}

std::string& trim_end(std::string& str, const std::locale& loc = std::locale()) {
    return trim_end(str, [&loc](const char c){ return std::isspace(c, loc); });
}

Podobnie możemy użyć funkcji std::iswspace() dla std::wstring itp.

Jeśli chcesz utworzyć nową sekwencję, która jest przyciętą kopią, możesz użyć oddzielnej funkcji:

template <typename Sequence, typename Pred>
Sequence trim_copy(Sequence seq, Pred pred) { // NOTE: passing seq by value
    trim(seq, pred);
    return seq;
}

Porównanie leksykograficzne

Dwa std::string s można porównać leksykograficznie za pomocą operatorów == != , < , <= , > I >= :

std::string str1 = "Foo";
std::string str2 = "Bar";

assert(!(str1 < str2));
assert(str > str2);
assert(!(str1 <= str2));
assert(str1 >= str2);
assert(!(str1 == str2));
assert(str1 != str2);

Wszystkie te funkcje używają podstawowej metody std::string::compare() do wykonania porównania i zwracają dla wygody wartości logiczne. Działanie tych funkcji można interpretować w następujący sposób, niezależnie od faktycznej implementacji:

  • operator == :

    Jeśli str1.length() == str2.length() i każda para znaków jest zgodna, wówczas zwraca true , w przeciwnym razie zwraca false .

  • operator != :

    Jeśli str1.length() != str2.length() lub jedna para znaków nie pasuje, zwraca true , w przeciwnym razie zwraca false .

  • operator < lub operator > :

    Znajduje pierwszą inną parę znaków, porównuje je, a następnie zwraca wynik logiczny.

  • operator <= lub operator >= :

    Znajduje pierwszą inną parę znaków, porównuje je, a następnie zwraca wynik logiczny.

Uwaga: Termin para znaków oznacza odpowiadające znaki w obu ciągach tych samych pozycji. Dla lepszego zrozumienia, jeśli dwa przykładowe ciągi to str1 i str2 , a ich długości wynoszą odpowiednio n i m , wówczas pary znaków obu ciągów oznaczają każdą parę str1[i] i str2[i] gdzie i = 0, 1, 2 str2[i] .., maks. (n, m) . Jeśli dla dowolnego znaku i, w którym odpowiedni znak nie istnieje, to znaczy, gdy i jest większy lub równy n lub m , zostanie uznany za najniższą wartość.


Oto przykład użycia < :

std::string str1 = "Barr";
std::string str2 = "Bar";

assert(str2 < str1);

Kroki są następujące:

  1. Porównaj pierwsze znaki, 'B' == 'B' - idź dalej.
  2. Porównaj drugie znaki, 'a' == 'a' - idź dalej.
  3. Porównaj trzecie znaki, 'r' == 'r' - idź dalej.
  4. Zakres str2 jest teraz wyczerpany, podczas gdy zasięg str1 wciąż ma znaki. Zatem str2 < str1 .

Konwersja do std :: wstring

W C ++ sekwencje znaków są reprezentowane przez specjalizację klasy std::basic_string rodzimym typem znaków. Dwie główne kolekcje zdefiniowane przez bibliotekę standardową to std::string i std::wstring :

  • std::string jest zbudowany z elementów typu char

  • std::wstring jest zbudowany z elementami typu wchar_t

Aby przekonwertować oba typy, użyj wstring_convert :

#include <string>
#include <codecvt>
#include <locale>

std::string input_str = "this is a -string-, which is a sequence based on the -char- type.";
std::wstring input_wstr = L"this is a -wide- string, which is based on the -wchar_t- type.";

// conversion
std::wstring str_turned_to_wstr = std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(input_str);

std::string wstr_turned_to_str = std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(input_wstr);

W celu poprawy użyteczności i / lub czytelności możesz zdefiniować funkcje do wykonania konwersji:

#include <string>
#include <codecvt>
#include <locale>

using convert_t = std::codecvt_utf8<wchar_t>;
std::wstring_convert<convert_t, wchar_t> strconverter;

std::string to_string(std::wstring wstr)
{
    return strconverter.to_bytes(wstr);
}

std::wstring to_wstring(std::string str)
{
    return strconverter.from_bytes(str);
}

Przykładowe użycie:

std::wstring a_wide_string = to_wstring("Hello World!");

Jest to z pewnością bardziej czytelne niż std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes("Hello World!") .


Pamiętaj, że char i wchar_t nie oznaczają kodowania i nie podają rozmiaru w bajtach. Na przykład wchar_t jest zwykle implementowany jako 2-bajtowy typ danych i zazwyczaj zawiera dane zakodowane w UTF-16 w systemie Windows (lub UCS-2 w wersjach wcześniejszych niż Windows 2000) oraz jako 4-bajtowy typ danych zakodowany w UTF-32 w Linux Jest to sprzeczne z nowszymi typami char16_t i char32_t , które zostały wprowadzone w C ++ 11 i mają gwarancję, że będą wystarczająco duże, aby pomieścić odpowiednio dowolny „znak” UTF16 lub UTF32 (a ściślej punkt kodowy ).

Korzystanie z klasy std :: string_view

C ++ 17

C ++ 17 wprowadza std::string_view , który jest po prostu nieposiadającym zakresu const char , implementowalnym jako para wskaźników lub wskaźnik i długość. Jest to lepszy typ parametru dla funkcji wymagających niemodyfikowalnych danych łańcuchowych. Przed wersją C ++ 17 istniały trzy opcje:

void foo(std::string const& s);      // pre-C++17, single argument, could incur
                                     // allocation if caller's data was not in a string
                                     // (e.g. string literal or vector<char> )

void foo(const char* s, size_t len); // pre-C++17, two arguments, have to pass them
                                     // both everywhere

void foo(const char* s);             // pre-C++17, single argument, but need to call
                                     // strlen()

template <class StringT>
void foo(StringT const& s);          // pre-C++17, caller can pass arbitrary char data
                                     // provider, but now foo() has to live in a header

Wszystkie te można zastąpić:

void foo(std::string_view s);        // post-C++17, single argument, tighter coupling
                                     // zero copies regardless of how caller is storing
                                     // the data

Zauważ, że std::string_view nie może modyfikować swoich danych bazowych .

string_view jest przydatny, gdy chcesz uniknąć niepotrzebnych kopii.

Oferuje użyteczny podzbiór funkcji, które wykonuje std::string , chociaż niektóre funkcje zachowują się inaczej:

std::string str = "lllloooonnnngggg sssstttrrriiinnnggg"; //A really long string

//Bad way - 'string::substr' returns a new string (expensive if the string is long)
std::cout << str.substr(15, 10) << '\n';

//Good way - No copies are created!
std::string_view view = str;

// string_view::substr returns a new string_view
std::cout << view.substr(15, 10) << '\n';

Pętli przez każdą postać

C ++ 11

std::string obsługuje iteratory, więc możesz użyć pętli opartej na dystansie do iteracji po każdym znaku:

std::string str = "Hello World!";
for (auto c : str)
    std::cout << c;

Można użyć „tradycyjne” for pętli do pętli każdej postaci:

std::string str = "Hello World!";
for (std::size_t i = 0; i < str.length(); ++i)
    std::cout << str[i];

Konwersja na typy całkowite / zmiennoprzecinkowe

Ciąg std::string zawierający liczbę można przekonwertować na typ całkowity lub zmiennoprzecinkowy za pomocą funkcji konwersji.

Zauważ, że wszystkie te funkcje przestają analizować ciąg wejściowy, gdy tylko napotkają znak nienumeryczny, więc "123abc" zostanie przekonwertowane na 123 .


Rodzina funkcji std::ato* konwertuje łańcuchy w stylu C (tablice znaków) na typy całkowite lub zmiennoprzecinkowe:

std::string ten = "10";

double num1 = std::atof(ten.c_str());
int num2 = std::atoi(ten.c_str());
long num3 = std::atol(ten.c_str());
C ++ 11
long long num4 = std::atoll(ten.c_str());

Jednak korzystanie z tych funkcji jest odradzane, ponieważ zwracają 0 jeśli nie parsują łańcucha. Jest to złe, ponieważ 0 może być również prawidłowym wynikiem, jeśli na przykład ciąg wejściowy to „0”, więc nie można ustalić, czy konwersja rzeczywiście się nie powiodła.

Nowsza rodzina funkcji std::sto* konwertuje std::string s na typy całkowite lub zmiennoprzecinkowe i zgłasza wyjątki, jeśli nie mogą parsować swoich danych wejściowych. Jeśli to możliwe, powinieneś użyć tych funkcji :

C ++ 11
std::string ten = "10";

int num1 = std::stoi(ten);
long num2 = std::stol(ten);
long long num3 = std::stoll(ten);

float num4 = std::stof(ten);
double num5 = std::stod(ten);
long double num6 = std::stold(ten);

Ponadto funkcje te obsługują również łańcuchy ósemkowe i szesnastkowe, w przeciwieństwie do rodziny std::ato* . Drugi parametr jest wskaźnikiem do pierwszego nieprzekształconego znaku w ciągu wejściowym (nie pokazano tutaj), a trzeci parametr jest podstawą do użycia. 0 to automatyczne wykrywanie liczby ósemkowej (zaczynającej się od 0 ) i szesnastkowej (zaczynającej się od 0x lub 0X ), a dowolną inną wartością jest podstawa do użycia

std::string ten = "10";
std::string ten_octal = "12";
std::string ten_hex = "0xA";

int num1 = std::stoi(ten, 0, 2); // Returns 2
int num2 = std::stoi(ten_octal, 0, 8); // Returns 10
long num3 = std::stol(ten_hex, 0, 16);  // Returns 10
long num4 = std::stol(ten_hex);  // Returns 0
long num5 = std::stol(ten_hex, 0, 0); // Returns 10 as it detects the leading 0x

Konwersja między kodowaniami znaków

Konwersja między kodowaniami jest łatwa w C ++ 11 i większość kompilatorów jest w stanie poradzić sobie z tym na wielu platformach poprzez <codecvt> i <locale> .

#include <iostream>
#include <codecvt>
#include <locale>
#include <string>
using namespace std;

int main() {
    // converts between wstring and utf8 string
    wstring_convert<codecvt_utf8_utf16<wchar_t>> wchar_to_utf8;
    // converts between u16string and utf8 string
    wstring_convert<codecvt_utf8_utf16<char16_t>, char16_t> utf16_to_utf8;
    
    wstring wstr = L"foobar";
    string utf8str = wchar_to_utf8.to_bytes(wstr);
    wstring wstr2 = wchar_to_utf8.from_bytes(utf8str);
    
    wcout << wstr << endl;
    cout << utf8str << endl;
    wcout << wstr2 << endl;
    
    u16string u16str = u"foobar";
    string utf8str2 = utf16_to_utf8.to_bytes(u16str);
    u16string u16str2 = utf16_to_utf8.from_bytes(utf8str2);
    
    return 0;
}

Pamiętaj, że Visual Studio 2015 zapewnia obsługę tych konwersji, ale błąd w ich implementacji biblioteki wymaga użycia innego szablonu dla wstring_convert podczas pracy z char16_t :

using utf16_char = unsigned short;
wstring_convert<codecvt_utf8_utf16<utf16_char>, utf16_char> conv_utf8_utf16;

void strings::utf16_to_utf8(const std::u16string& utf16, std::string& utf8)
{
  std::basic_string<utf16_char> tmp;
  tmp.resize(utf16.length());
  std::copy(utf16.begin(), utf16.end(), tmp.begin());
  utf8 = conv_utf8_utf16.to_bytes(tmp);
}
void strings::utf8_to_utf16(const std::string& utf8, std::u16string& utf16)
{ 
  std::basic_string<utf16_char> tmp = conv_utf8_utf16.from_bytes(utf8);
  utf16.clear();
  utf16.resize(tmp.length());
  std::copy(tmp.begin(), tmp.end(), utf16.begin());
}

Sprawdzanie, czy łańcuch jest prefiksem innego

C ++ 14

W C ++ 14 można to łatwo zrobić przez std::mismatch który zwraca pierwszą parę niezgodności z dwóch zakresów:

std::string prefix = "foo";
std::string string = "foobar";

bool isPrefix = std::mismatch(prefix.begin(), prefix.end(),
    string.begin(), string.end()).first == prefix.end();

Zauważ, że półtonowa wersja mismatch() istniała przed C ++ 14, ale jest to niebezpieczne w przypadku, gdy drugi ciąg jest krótszy z dwóch.

C ++ 14

Nadal możemy używać wersji std::mismatch() półtorej odległości, ale najpierw musimy sprawdzić, czy pierwszy ciąg znaków jest co najwyżej tak duży, jak drugi:

bool isPrefix = prefix.size() <= string.size() &&
    std::mismatch(prefix.begin(), prefix.end(),
        string.begin(), string.end()).first == prefix.end();
C ++ 17

Za pomocą std::string_view możemy napisać bezpośrednie porównanie, które chcemy, bez obawy o narzut związany z alokacją lub wykonywanie kopii:

bool isPrefix(std::string_view prefix, std::string_view full)
{
    return prefix == full.substr(0, prefix.size());
}

Konwersja do std :: string

std::ostringstream można wykorzystać do konwersji dowolnego typu strumienia do reprezentacji ciągu, wstawiając obiekt do obiektu std::ostringstream (z operatorem wstawiania strumienia << ), a następnie konwertując cały std::ostringstream do std::string .

Na przykład int :

#include <sstream>

int main()
{
    int val = 4;
    std::ostringstream str;
    str << val;
    std::string converted = str.str();
    return 0;
}

Pisanie własnej funkcji konwersji jest proste:

template<class T>
std::string toString(const T& x)
{
  std::ostringstream ss;
  ss << x;
  return ss.str();
}

działa, ale nie nadaje się do kodu krytycznego dla wydajności.

Klasy zdefiniowane przez użytkownika mogą w razie potrzeby zaimplementować operator wstawiania strumienia:

std::ostream operator<<( std::ostream& out, const A& a )
{
    // write a string representation of a to out
    return out; 
}
C ++ 11

Oprócz strumieni, od C ++ 11 możesz także użyć funkcji std::to_string (i std::to_wstring ), która jest przeciążona dla wszystkich podstawowych typów i zwraca ciąg reprezentujący jej parametr.

std::string s = to_string(0x12f3);  // after this the string s contains "4851"


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow