Sprawdź, czy ciąg zawiera ciąg w C ++

493

Mam zmienną typu std::string. Chcę sprawdzić, czy zawiera pewne std::string. Jak mam to zrobić?

Czy istnieje funkcja, która zwraca true, jeśli ciąg zostanie znaleziony, a false, jeśli nie jest?

neuromancer
źródło
6
Masz na myśli ciąg char * lub ciąg z STL?
Antares
1
To nie jest ciąg znaków *. Musiałem #include <ciąg>, aby go użyć.
neuromancer
1
Niektóre rozwiązania używają s2 dla ciągu, który chcę znaleźć. Czy nadal będzie działać, jeśli użyję czegoś takiego jak „to jest ciąg” zamiast s2?
neuromancer
2
Tak, ponieważ istnieje konstruktor literl łańcucha dla typu std :: string.
18
Ktoś proszę o propozycję dodania std::basic_string::containsdo stdlib.
emlai

Odpowiedzi:

722

Użyj std::string::findw następujący sposób:

if (s1.find(s2) != std::string::npos) {
    std::cout << "found!" << '\n';
}

Uwaga: „znaleziono!” zostanie wydrukowany, jeśli s2jest podciągiem s1, zarówno s1i s2są typu std::string.

Guy Avraham
źródło
117

Możesz spróbować użyć findfunkcji:

string str ("There are two needles in this haystack.");
string str2 ("needle");

if (str.find(str2) != string::npos) {
//.. found.
} 
kodaddict
źródło
27

Właściwie możesz spróbować użyć biblioteki doładowania, myślę, że std :: string nie zapewnia wystarczającej metody do wykonania wszystkich typowych operacji na łańcuchach. W boost, możesz po prostu użyć boost::algorithm::contains:

#include <string>
#include <boost/algorithm/string.hpp>

int main() {
    std::string s("gengjiawen");
    std::string t("geng");
    bool b = boost::algorithm::contains(s, t);
    std::cout << b << std::endl;
    return 0;
}
Geng Jiawen
źródło
33
„Myślę, że std :: string nie dostarcza wystarczającej metody do wykonania wszystkich typowych operacji na łańcuchach”. Ale istnieje findmetoda na dokładnie to zadanie. Nie ma potrzeby wprowadzania zależności biblioteki.
stefan
8
@stefan, masz rację, istnieje metoda znajdowania, ale co z dzieleniem, zastępowaniem i wieloma innymi pięcioliniami. Możesz porównać std :: string do api-string w Java.PS:Myślę też, że zawiera jest znacznie bardziej elegancki niż znajdź, aby sprawdzić, czy ciąg zawiera inny ciąg.
Geng Jiawen,
1
Jest to także krótkie i łatwiejsze do zapamiętania. Cpp 17 ma dodaną obsługę systemu plików. Mam nadzieję, że Cpp 2x też zrobi coś dla łańcucha. Bardzo bolesne jest brak obsługi podstawowych metod łańcuchowych we współczesnym CPP.
Geng Jiawen,
1
Czy naprawdę potrzebujesz „zastosowań”? Kiedy czytam ten kod, nie mam pojęcia, czy containsjest std::containslub boost::contains, co wydaje się znaczącą wadą. Chyba std :: zawiera obecnie nie istnieje, ale nie jestem pewien, czy rozsądne jest założenie, że czytelnik zapamiętał wszystko, co jest w standardzie. I std::containsmoże równie dobrze istnieć w jakiejś przyszłej wersji c ++, która złamałaby ten program.
Don Hatch
12

Możesz tego spróbować

string s1 = "Hello";
string s2 = "el";
if(strstr(s1.c_str(),s2.c_str()))
{
   cout << " S1 Contains S2";
}
HappyTran
źródło
4

W przypadku, gdy funkcjonalność ma kluczowe znaczenie dla systemu, w rzeczywistości korzystne jest użycie starej strstrmetody. Ta std::searchmetoda algorithmjest najwolniejsza z możliwych. Sądzę, że stworzenie iteratorów zajmuje dużo czasu.

Kod, którego użyłem do pomiaru czasu, to:

#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <random>
#include <chrono>

std::string randomString( size_t len );

int main(int argc, char* argv[])
{
        using namespace std::chrono;

        const size_t haystacksCount = 200000;
        std::string haystacks[haystacksCount];
        std::string needle = "hello";

        bool sink = true;

        high_resolution_clock::time_point start, end;
        duration<double> timespan;

        int sizes[10] = { 10, 20, 40, 80, 160, 320, 640, 1280, 5120, 10240 };

        for(int s=0; s<10; ++s)
        {
                std::cout << std::endl << "Generating " << haystacksCount << " random haystacks of size " << sizes[s] << std::endl;
                for(size_t i=0; i<haystacksCount; ++i)
                {
                        haystacks[i] = randomString(sizes[s]);
                }

                std::cout << "Starting std::string.find approach" << std::endl;
                start = high_resolution_clock::now();
                for(size_t i=0; i<haystacksCount; ++i)
                {
                        if(haystacks[i].find(needle) != std::string::npos)
                        {
                                sink = !sink; // useless action
                        }
                }
                end = high_resolution_clock::now();
                timespan = duration_cast<duration<double>>(end-start);
                std::cout << "Processing of " << haystacksCount << " elements took " << timespan.count() << " seconds." << std::endl;

                std::cout << "Starting strstr approach" << std::endl;
                start = high_resolution_clock::now();
                for(size_t i=0; i<haystacksCount; ++i)
                {
                        if(strstr(haystacks[i].c_str(), needle.c_str()))
                        {
                                sink = !sink; // useless action
                        }
                }
                end = high_resolution_clock::now();
                timespan = duration_cast<duration<double>>(end-start);
                std::cout << "Processing of " << haystacksCount << " elements took " << timespan.count() << " seconds." << std::endl;

                std::cout << "Starting std::search approach" << std::endl;
                start = high_resolution_clock::now();
                for(size_t i=0; i<haystacksCount; ++i)
                {
                        if(std::search(haystacks[i].begin(), haystacks[i].end(), needle.begin(), needle.end()) != haystacks[i].end())
                        {
                                sink = !sink; // useless action
                        }
                }
                end = high_resolution_clock::now();
                timespan = duration_cast<duration<double>>(end-start);
                std::cout << "Processing of " << haystacksCount << " elements took " << timespan.count() << " seconds." << std::endl;
        }

        return 0;
}

std::string randomString( size_t len)
{
        static const char charset[] = "abcdefghijklmnopqrstuvwxyz";
        static const int charsetLen = sizeof(charset) - 1;
        static std::default_random_engine rng(std::random_device{}());
        static std::uniform_int_distribution<> dist(0, charsetLen);
        auto randChar = [charset, &dist, &rng]() -> char
        {
                return charset[ dist(rng) ];
        };

        std::string result(len, 0);
        std::generate_n(result.begin(), len, randChar);
        return result;
}

Tutaj generuję losowo haystacksi wyszukuję w nich needle. Liczba stogów siana jest ustawiona, ale długość łańcuchów w każdym stogu siana jest zwiększana z 10 na początku do 10240 na końcu. Przez większość czasu program faktycznie generuje losowe ciągi, ale należy się tego spodziewać.

Dane wyjściowe to:

Generating 200000 random haystacks of size 10
Starting std::string.find approach
Processing of 200000 elements took 0.00358503 seconds.
Starting strstr approach
Processing of 200000 elements took 0.0022727 seconds.
Starting std::search approach
Processing of 200000 elements took 0.0346258 seconds.

Generating 200000 random haystacks of size 20
Starting std::string.find approach
Processing of 200000 elements took 0.00480959 seconds.
Starting strstr approach
Processing of 200000 elements took 0.00236199 seconds.
Starting std::search approach
Processing of 200000 elements took 0.0586416 seconds.

Generating 200000 random haystacks of size 40
Starting std::string.find approach
Processing of 200000 elements took 0.0082571 seconds.
Starting strstr approach
Processing of 200000 elements took 0.00341435 seconds.
Starting std::search approach
Processing of 200000 elements took 0.0952996 seconds.

Generating 200000 random haystacks of size 80
Starting std::string.find approach
Processing of 200000 elements took 0.0148288 seconds.
Starting strstr approach
Processing of 200000 elements took 0.00399263 seconds.
Starting std::search approach
Processing of 200000 elements took 0.175945 seconds.

Generating 200000 random haystacks of size 160
Starting std::string.find approach
Processing of 200000 elements took 0.0293496 seconds.
Starting strstr approach
Processing of 200000 elements took 0.00504251 seconds.
Starting std::search approach
Processing of 200000 elements took 0.343452 seconds.

Generating 200000 random haystacks of size 320
Starting std::string.find approach
Processing of 200000 elements took 0.0522893 seconds.
Starting strstr approach
Processing of 200000 elements took 0.00850485 seconds.
Starting std::search approach
Processing of 200000 elements took 0.64133 seconds.

Generating 200000 random haystacks of size 640
Starting std::string.find approach
Processing of 200000 elements took 0.102082 seconds.
Starting strstr approach
Processing of 200000 elements took 0.00925799 seconds.
Starting std::search approach
Processing of 200000 elements took 1.26321 seconds.

Generating 200000 random haystacks of size 1280
Starting std::string.find approach
Processing of 200000 elements took 0.208057 seconds.
Starting strstr approach
Processing of 200000 elements took 0.0105039 seconds.
Starting std::search approach
Processing of 200000 elements took 2.57404 seconds.

Generating 200000 random haystacks of size 5120
Starting std::string.find approach
Processing of 200000 elements took 0.798496 seconds.
Starting strstr approach
Processing of 200000 elements took 0.0137969 seconds.
Starting std::search approach
Processing of 200000 elements took 10.3573 seconds.

Generating 200000 random haystacks of size 10240
Starting std::string.find approach
Processing of 200000 elements took 1.58171 seconds.
Starting strstr approach
Processing of 200000 elements took 0.0143111 seconds.
Starting std::search approach
Processing of 200000 elements took 20.4163 seconds.
v010dya
źródło
Krótsza wersja odpowiedzi to: użycie c zamiast c ++ :)
r0ng
3

Jeśli nie chcesz używać standardowych funkcji bibliotecznych, poniżej znajduje się jedno rozwiązanie.

#include <iostream>
#include <string>

bool CheckSubstring(std::string firstString, std::string secondString){
    if(secondString.size() > firstString.size())
        return false;

    for (int i = 0; i < firstString.size(); i++){
        int j = 0;
        // If the first characters match
        if(firstString[i] == secondString[j]){
            int k = i;
            while (firstString[i] == secondString[j] && j < secondString.size()){
                j++;
                i++;
            }
            if (j == secondString.size())
                return true;
            else // Re-initialize i to its original value
                i = k;
        }
    }
    return false;
}

int main(){
    std::string firstString, secondString;

    std::cout << "Enter first string:";
    std::getline(std::cin, firstString);

    std::cout << "Enter second string:";
    std::getline(std::cin, secondString);

    if(CheckSubstring(firstString, secondString))
        std::cout << "Second string is a substring of the frist string.\n";
    else
        std::cout << "Second string is not a substring of the first string.\n";

    return 0;
}
Testowanie123
źródło
6
Używasz już std :: string, stąd twój kod już zależy od std lib. Nie widzę żadnego powodu, aby unikać przyjętego rozwiązania za pomocą std :: string :: find.
b00n12
Tak, to dobra uwaga. Nie myślałem, że kiedy to napisałem. Myślę, że to, co pomyślałem, kiedy to napisałem, to może jak po prostu uniknąć użycia std :: find.
Testowanie 123
3
Tylko dla przyszłych gości: ten algorytm nie jest właściwie poprawny. Ponieważ „i” nigdy nie wraca po nieudanym dopasowaniu podciągu, niektóre przypadki nie są dopasowane, na przykład rozważ: aaabc, aab
sAm_vdP
1
To ma kilka błędów. CheckSubstring(std::string firstString, std::string secondString)głębokie kopie obu ciągów przekazywanych do funkcji, co jest kosztowne, szczególnie w przypadku dłuższych ciągów wymagających alokacji sterty. Dalej, można powiedzieć, zadzwoń CheckSubstring("XYZab", "ab\0\0")- w whilepętli zakończy się porównując ado a, bdo b, niejawny NUL na końcu pierwszego ciągu do wyraźnej NUL na sekundę, to będą czytać poza buforem pierwszego ciągu, posiadające niezdefiniowanej zachowanie. Aby to naprawić użyj for (... i <= firstString.size () - secondString (). Size (); ...) `.
Tony Delroy,
1

Jeśli rozmiar ciągów znaków jest stosunkowo duży (setki bajtów lub więcej) i dostępne jest c ++ 17, możesz użyć wyszukiwarki Boyer-Moore-Horspool (przykład z cppreference.com):

#include <iostream>
#include <string>
#include <algorithm>
#include <functional>

int main()
{
    std::string in = "Lorem ipsum dolor sit amet, consectetur adipiscing elit,"
                     " sed do eiusmod tempor incididunt ut labore et dolore magna aliqua";
    std::string needle = "pisci";
    auto it = std::search(in.begin(), in.end(),
                   std::boyer_moore_searcher(
                       needle.begin(), needle.end()));
    if(it != in.end())
        std::cout << "The string " << needle << " found at offset "
                  << it - in.begin() << '\n';
    else
        std::cout << "The string " << needle << " not found\n";
}
Konstantin Stupnik
źródło
3
Znaki czasu. W dawnych czasach ktoś oferował funkcję bool contains(const std::string& haystack, const std::string& needle). Obecnie oferują zestaw puzzli nazwanych imionami niektórych niejasnych autorów niejasnych dokumentów, aby wyglądały bardziej jak informatyka ...
BitTickler,
0

Możesz także użyć przestrzeni nazw System. Następnie możesz użyć metody zawiera.

#include <iostream>
using namespace System;

int main(){
    String ^ wholeString = "My name is Malindu";

    if(wholeString->ToLower()->Contains("malindu")){
        std::cout<<"Found";
    }
    else{
        std::cout<<"Not Found";
    }
}
Malindu Dilanka
źródło
Ta odpowiedź dotyczy wyłącznie zastrzeżonego rozszerzenia Microsoft C ++ C ++ / CX lub C ++ / CLI
H. Al-Amri
1
tak, przepraszam, nie wiedziałem, że to działa tylko do pewnego dnia po opublikowaniu.
Malindu Dilanka
-1

To jest prosta funkcja

bool find(string line, string sWord)
{
    bool flag = false;
    int index = 0, i, helper = 0;
    for (i = 0; i < line.size(); i++)
    {
        if (sWord.at(index) == line.at(i))
        {
            if (flag == false)
            {
                flag = true;
                helper = i;
            }
            index++;
        }
        else
        {
            flag = false;
            index = 0;
        }
        if (index == sWord.size())
        {
            break;
        }
    }
    if ((i+1-helper) == index)
    {
        return true;
    }
    return false;
}
neda
źródło
4
Witaj, witaj w SO. Czy możesz edytować swoją odpowiedź i dodać komentarz na temat tego, jak to działa i czym różni się od innych odpowiedzi? Dziękuję Ci!
Fabio mówi Przywróć Monikę
-1
#include <algorithm>        // std::search
#include <string>
using std::search; using std::count; using std::string;

int main() {
    string mystring = "The needle in the haystack";
    string str = "needle";
    string::const_iterator it;
    it = search(mystring.begin(), mystring.end(), 
                str.begin(), str.end()) != mystring.end();

    // if string is found... returns iterator to str's first element in mystring
    // if string is not found... returns iterator to mystring.end()

if (it != mystring.end())
    // string is found
else
    // not found

return 0;
}
zaonline
źródło
11
Staraj się unikać po prostu odrzucania kodu jako odpowiedzi i spróbuj wyjaśnić, co robi i dlaczego. Twój kod może nie być oczywisty dla osób, które nie mają odpowiedniego doświadczenia w programowaniu. Edytuj swoją odpowiedź, aby uwzględnić wyjaśnienie, kontekst i spróbuj wspomnieć o wszelkich ograniczeniach, założeniach lub uproszczeniach w swojej odpowiedzi.
Sᴀᴍ Onᴇᴌᴀ
Dziękujemy za wyjaśnienie kodu, używanie usingtylko wymaganych funkcji i nie zrzutowanie całej przestrzeni nazw do przestrzeni globalnej. Jeśli chodzi o komentarz @ SᴀᴍOnᴇᴌᴀ, myślę, że użytkownik nie przeczytał komentarzy w twoim kodzie.
v010dya
-2

Z tylu odpowiedzi na tej stronie nie znalazłem jasnej odpowiedzi, więc w ciągu 5-10 minut sam wymyśliłem odpowiedź. Ale można to zrobić w dwóch przypadkach:

  1. Albo WIESZ pozycję podciągu, którego szukasz w ciągu
  2. Albo nie znasz pozycji i jej szukasz, char po char ...

Załóżmy więc, że szukamy podciągu „cd” w ciągu „abcde” i używamy najprostszej wbudowanej funkcji substr w C ++

Za 1:

#include <iostream>
#include <string>

    using namespace std;
int i;

int main()
{
    string a = "abcde";
    string b = a.substr(2,2);    // 2 will be c. Why? because we start counting from 0 in a string, not from 1.

    cout << "substring of a is: " << b << endl;
    return 0;
}

dla 2:

#include <iostream>
#include <string>

using namespace std;
int i;

int main()
{
    string a = "abcde";

    for (i=0;i<a.length(); i++)
    {
        if (a.substr(i,2) == "cd")
        {
        cout << "substring of a is: " << a.substr(i,2) << endl;    // i will iterate from 0 to 5 and will display the substring only when the condition is fullfilled 
        }
    }
    return 0;
}
użytkownik7655194
źródło
2
W jaki sposób najlepsza odpowiedź („use std :: string :: find”), opublikowana 8 lat wcześniej, nie była wystarczająco jasna?
Steve Smith
-3

Zamiast tego możemy użyć tej metody. Tylko przykład z moich projektów. Odwołaj się do kodu. Niektóre dodatki są również uwzględnione.

Spójrz na instrukcje if!

/*
Every C++ program should have an entry point. Usually, this is the main function.
Every C++ Statement ends with a ';' (semi-colon)
But, pre-processor statements do not have ';'s at end.
Also, every console program can be ended using "cin.get();" statement, so that the console won't exit instantly.
*/

#include <string>
#include <bits/stdc++.h> //Can Use instead of iostream. Also should be included to use the transform function.

using namespace std;
int main(){ //The main function. This runs first in every program.

    string input;

    while(input!="exit"){
        cin>>input;
        transform(input.begin(),input.end(),input.begin(),::tolower); //Converts to lowercase.

        if(input.find("name") != std::string::npos){ //Gets a boolean value regarding the availability of the said text.
            cout<<"My Name is AI \n";
        }

        if(input.find("age") != std::string::npos){
            cout<<"My Age is 2 minutes \n";
        }
    }

}
Malindu Dilanka
źródło
Przepraszam, nie widziałem, że ktoś opublikował to samo, co poprzednio.
Malindu Dilanka
1
„Subskrybuj mnie na YouTube” można uznać za spam. Pamiętaj o tym w przyszłości. Przeczytaj także Jak odpowiedzieć i jak nie być spamerem
Zoe