porównanie std :: string (sprawdź, czy ciąg zaczyna się od innego ciągu)

90

Muszę sprawdzić, czy ciąg std: zaczyna się od „xyz”. Jak to zrobić bez przeszukiwania całego ciągu lub tworzenia tymczasowych ciągów za pomocą funkcji substr ().

jackhab
źródło

Odpowiedzi:

164

Użyłbym metody porównawczej:

std::string s("xyzblahblah");
std::string t("xyz")

if (s.compare(0, t.length(), t) == 0)
{
// ok
}
Wacek
źródło
3
Dlaczego po prostu nie użyjesz s.compare (t)?
Franck Mesirard
5
@FranckMesirard: To dlatego, że domyślnie porównanie spróbuje porównać całą długość przekazanego ciągu z danymi składowymi i zwróci false, podczas gdy podanie długości jako długości przekazanego parametru sprawi, że zwróci on wartość true (co oznacza std :: basic_string :: Porównanie , gdy jest używane z przesunięciem i długością, może być użyte podobnie jak String.BeginsWith () w innych bibliotekach.) Bez przesunięcia i długości nie byłoby to prawdą.
legends2k
1
To zwraca prawdę, jeśli t jest puste.
szybowiec
14
@gliderkite Tak jak powinno ... pusty ciąg jest początkowym przedrostkiem każdego ciągu.
Jim Balter,
1
Tak, jak powinno, jest poprawne ... Jeśli chcesz wykluczyć puste ciągi: if (! T.empty () &&! S.compare (0, t.length (), t))
ericcurtin
14

Podejściem, które mogłoby być bardziej zgodne z duchem Biblioteki Standardowej, byłoby zdefiniowanie własnego algorytmu begin_withm.

#include <algorithm>
using namespace std;


template<class TContainer>
bool begins_with(const TContainer& input, const TContainer& match)
{
    return input.size() >= match.size()
        && equal(match.begin(), match.end(), input.begin());
}

Zapewnia to prostszy interfejs do kodu klienta i jest kompatybilny z większością kontenerów biblioteki standardowej.

Neutrino
źródło
Fajne! Należy to dodać, aby zwiększyć!
David
2
@David: Jeśli boost jest dozwoloną zależnością, zobacz boost :: gorithm :: started_with - predykat 'Starts with'
Gabor
10

Zajrzyj do biblioteki Boost's String Algo , która ma wiele przydatnych funkcji, takich jak start_with, istart_with (bez rozróżniania wielkości liter) itp. Jeśli chcesz używać tylko części bibliotek boost w swoim projekcie, możesz użyć narzędzia bcp do kopiowania tylko potrzebne pliki

Alex Ott
źródło
4

Wygląda na to, że std :: string :: started_with znajduje się wewnątrz C ++ 20, tymczasem można użyć std :: string :: find

std::string s1("xyzblahblah");
std::string s2("xyz")

if (s1.find(s2) == 0)
{
   // ok, s1 starts with s2
}
Alejadro Xalabarder
źródło
1
Jest to znacznie lepsze niż zaakceptowana odpowiedź przy użyciu, std::string::compareponieważ ułatwia sprawdzenie, czy ciąg zaczyna się od literału, bez konieczności powtarzania samego literału w celu znalezienia jego rozmiaru. Dziękujemy za wskazanie bezpośredniego rozwiązania C ++ 20.
Ruslan,
Jeśli s1 nie zaczyna się od s2, nadal będzie próbować dopasować go później, co nie jest tak dobre, jak compare ().
A117
0

Czuję, że nie rozumiem w pełni twojego pytania. Wygląda na to, że powinno być trywialne:

s[0]=='x' && s[1]=='y' && s[2]=='z'

Dotyczy to tylko (najwyżej) pierwszych trzech znaków. Uogólnienie dla łańcucha, który jest nieznany w czasie kompilacji, wymagałoby zastąpienia powyższego pętlą:

// look for t at the start of s
for (int i=0; i<s.length(); i++)
{
  if (s[i]!=t[i])
    return false;
}
1800 INFORMACJE
źródło
Cóż, wiem, jak porównywać ciągi znaków przy użyciu funkcji C. Moje pytanie dotyczyło zrobienia tego w sposób obiektowy za pomocą C ++ STL.
jackhab
Nie użyto tutaj żadnej funkcji C. Biblioteka standardowa nie zabrania ci pisania własnych instrukcji.
6
a co jeśli t jest krótsze niż s?
vidstige,
@jackhab Autor STL mówi: "STL nie jest zorientowany obiektowo. Myślę, że zorientowanie obiektowe jest prawie tak samo mistyfikacją jak sztuczna inteligencja". - stlport.org/resources/StepanovUSA.html
Jim Balter
1
@vidstige Następnie pętla kończy się, gdy napotka kończącą wartość NUL w t.
Jim Balter,