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 ().

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
}

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.


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


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
}

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

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,
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.