/* Jak to naprawić? */
#include <iostream>
#include <sstream> // Do dzielenia wyrazów na słowa.
#include <string>
#include <fstream>
#include <vector> // Do przechowania listy wyrazów.
using namespace std;
int i { 0 }; //:: patrz (1)
bool czy_ma_a( const string& slowo_A , const int& szukajOd_A = 0 ) //:: (2)
{
string a = "a";
for ( int j = szukajOd_A ; j < slowo_A.length() ; j++ )
{
if ( slowo_A[ j ] == a[ 0 ] ) //:: (3) (3a)
{
if( ( slowo_A.length() - j ) < a.length() ) return false; //:: (4)
else
{
for ( int a_index = 1 ; a_index < a.length() ; a_index++ )
{
if( slowo_A[ j + a_index ] != a[ a_index ] ) return czy_ma_a( slowo_A , j + 1 ) ; //:: (5)
}
return true;
}
}
}
return false;
}
int main()
{
fstream plik;
plik.open( "dane.txt" , ios::in );
if( plik.good() )
{
string napis {};
while( !plik.eof() )
{
getline( plik , napis );
vector< string > lista_slow {};
stringstream ss;
string slowo {};
ss.str( napis );
while( ss >> slowo ) lista_slow.push_back( slowo );
for( auto& element : lista_slow ) //:: (6)
{
if( czy_ma_a( element ) ) i++; // :: (7)
}
}
cout << "W pliku znajduja sie " << i << " slowa z litera a";
} else cout << "Error! Nie udalo otworzyc sie pliku!" << endl;
plik.close();
return( 0 );
}
/*
( 1 ) Inicjalizaja za pomocą std::initializer_list.
( 2 ) ( porada ) Przesłanie argumentu przez kopię jest wolniejsze niż przez referencję.
( 3 ) Jeżeli w słowie znajduje się pierwsza litera szukanej frazy to sprawdźmy czy kolejne też się zgadzają.
( 3a ) Jeżeli stała "a" ma być zawsze jedno literowa to tutaj można zakończyć szukanie poprzez return true;
( 4 ) warunek dający pewność, że odwołanie slowo_A[ j + a_index ] nie wyjdzie poza granicę stringa słowo_A.
( 5 ) Teraz sprawdzamy kolejne ciąg w wyrazie zaczynający się od a[0] bo np. wyraz wz w wyrazie wxwywz rozpoczyna sie od trzeciego wystapienia w. Dla ułatwienia korzystamy z wywołania rekurencyjnego, czyli funkcja wywołuje samą siebie.
( 6 ) auto, czyli automatyczne rozpoznawanie typu. To prośba do kompilatora, aby na podstawie typu inicjalizatora sam automatycznie się rozeznał o jaki typ obiektu chodzi. Przydatne gdy nazwy typów są długie, ale równie dobrze można użyć nazwy typu czyli klasy "string".
( 7 ) ( porada ) "==true" można pominąć.
Inne uwagi:
1. W twoim kodzie linia_28 return 0; nigdy nie będzie wywołana bo poprzedza ją już inny return.
*/
/* Jak to zrobić krócej? */
/*
Zawsze warto sprawdzić czy używana przez nas klasa nie ma już funkcji, która odpowiada naszym potrzebom.
W tym wypadku można posłużyć się funkcją find() z klasy string. Wtedy nasza funkcja wyglądać może tak:
bool czy_ma_a( const string& slowo_A )
{
string a = "a";
return ( slowo_A.find( a ) != string::npos ) ? true : false;
}
*/
Literatura:
Jerzy Grębosz "Opus Magnum C++11".