Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Wyszukiwanie frazy w pliku - niepoprawny wynik [ROZWIĄZANY]

Ostatnio zmodyfikowano 2019-02-14 22:22
Autor Wiadomość
tirurir
Temat założony przez niniejszego użytkownika
Wyszukiwanie frazy w pliku - niepoprawny wynik [ROZWIĄZANY]
» 2019-02-13 16:44:39
Od paru dni staram się naprawić błędy z programem który ma zliczać ilość wystąpienia danej frazy w tekście. Piszę w C. Program się kompiluje ale niestety wyniki które zwraca odbiegają od prawdy.
Najpewniej popełniłem jakiś błąd logiczny i jestem ślepy na swój błąd. Wszelka pomoc bardzo mile widziana :)

Jeśli ktoś zechciałby przetestować program u siebie pamiętajcie by utworzyć i wypełnić przykładowym tekstem plik file1.txt i edytować jego ścieżce w linijce nr35 "source = fopen("D:file1.txt", "r");". Kod starałem się pisać od zera tzn nie wykorzystując funkcji takich jak strstr. Znajduje się w nim kilka testów printf, być może okażą się pomocne.

===UWAGA: POPRAWNIE DZIAŁAJĄCY KOD ZNAJDUJE SIĘ NA DRUGIEJ STRONIE WĄTKU. PONIŻEJ POZOSTAWIAM WADLIWY KOD BEZ ZMIAN GDYBY KTOKOLWIEK CZYTAJĄC WĄTEK Z JAKIEGOŚ POWODU ZERKAŁ WŁAŚNIE DO NIEGO===

C/C++
#define _CRT_SECURE_NO_WARNINGS //prevents 'use scanf_s warning' in Visual Studio
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
////////
int search( char arr[], int fileLen, char phrase[] ) //count all occurances of the phrase in arr
{
    int i, matchCount = 0; //iteration counter, matching characters counter
    int count = 0; //occarances counter
    for( i = 0; i <( fileLen - strlen( phrase ) + 1 ); i++ )
    {
        if( arr[ i ] == phrase[ i % strlen( phrase ) ] )
        {
            matchCount++;
            if( matchCount ==( strlen( phrase ) ) )
            {
                count++;
                matchCount = 0; //reset matching characters number
            }
        }
    }
    return count;
}
////////
int main() {
    ////////VARIABLES (not including phrase)
    int count = 0;
    int i = 0;
    char buf[ 256 ]; //buffer for test input
    char arr[ 512 ]; // char arr[512];
    int fileLen = 512; //array (arr) size
    int length; //lenght of a phrase
    ////////OPEN FILE
    FILE * source;
    source = fopen( "D:file1.txt", "r" ); //open source
    while( fgets( arr, fileLen, source ) != NULL ); //read file.
    ////////ASK USER FOR TEXT TO FIND
    printf( "what phrase should i look for?\n\n" );
    scanf( "%s", buf );
    length = strlen( buf );
    printf( "Length of the typed phrase: %d,TEST\n", length ); //////TEST
    ////////WRITE FROM BUFFER TO PHRASE
    char * phrase = malloc( sizeof( char ) *( length + 1 ) ); //allocate memory fot phrase
    strncpy( phrase, buf, sizeof( phrase ) - 1 ); //uses strncpy the safe way
    phrase[ sizeof( phrase ) - 1 ] = '\0';
    printf( "You have typed: %s,TEST\n", phrase ); //////TEST
    ////////SEARCHING FOR THE PHRASE
    if( length <= fileLen )
    {
        count = search( arr, fileLen, phrase );
        printf( "I have found such phrase %d times - TEST\n", search( arr, fileLen, phrase ) ); //////TEST
        printf( "I have found such phrase %d times.\n", count );
    }
    else
    {
        printf( "The phrase you have entered is longer than number of characters in the source file. Phrase was found 0 times.\n" );
    }
    ////////CLOSE
    fclose( source );
    system( "pause" );
    return 0;
}
P-173946
pekfos
» 2019-02-13 18:00:27
C/C++
if( arr[ i ] == phrase[ i % strlen( phrase ) ] )
Ten warunek nie ma sensu. Powinno być
arr[ i ] == phrase[ matchCount ]
 i do tego warunku powinno być else które skoryguje wartości i i matchCount.

I nie wywołuj bez przerwy strlen(), to nie są darmowe rzeczy..
P-173948
tirurir
Temat założony przez niniejszego użytkownika
» 2019-02-13 19:23:20
Racja, rozpisałem sobie poniżej i faktycznie warunek działał troszkę inaczej niż powinien.
Przykład: arr = "tekstlorem" phrase = "tekst". długość phrase to 5
arr[0] = "t" phrase [0] = "t" matchCount = 1 count=0
arr[1] = "e" phrase [1] = "e" matchCount = 2 count=0
arr[2] = "k" phrase [2] = "k" matchCount = 3 count=0
arr[3] = "s" phrase [3] = "s" matchCount = 4 count=0
arr[4] = "t" phrase [4] = "t" matchCount = 5, matchCount == strlen(phrase)więc count=1, matchCount = 0
arr[5] = "l" phrase [0] = "t" matchCount = 0 count=1
arr[6] = "o" phrase [0] = "e" matchCount = 0 count=1
arr[7] = "r" phrase [0] = "k" matchCount = 0 count=1
arr[8] = "e" phrase [0] = "s" matchCount = 0 count=1
arr[9] = "m" phrase [0] = "s" matchCount = 0 count=1
Stąd jeśli taki matchCount jest równy długości phrase oraz arr[matchCount] == phrase[matchCount] wtedy zliczone jest jedno powtórzenie frazy w tekście.

Widzę teraz, że zapomniałem zerować matchCout gdy pierwszy if się nie zgadza ale niezbyt wiem dlaczego licznik i powinienem zresetować. Kod co prawda nie jeszcze nie działa ale i ma być tylko licznikiem który przeskakuje po całej tablicy arr.
Kiedy printowałem w pętli matchCount dostawałem maksymalnie wartość 2, a pytałem o frazę "tekst" dla pliku który zawiera "tekst tekst te" a później lorem ipsum po łacinie i angielsku. Powinien na samym początku mieć ze 2 razy wartość 5 oraz raz wartość 1.

Strleny usunę gdy funkcja będzie gotowa, nie chciałem mieć zbyt wielu parametrów ale później wykorzystam po prostu zmienną length która przechowa długość phrase.

Wstawiam kod funkcji aby nie było nieporozumień:
C/C++
int search( char arr[], int fileLen, char phrase[] ) //count all occurances of the phrase in arr
{
    int i, matchCount = 0; //iteration counter, matching characters counter
    int count = 0; //occarances counter
    for( i = 0; i <( fileLen - strlen( phrase ) + 1 ); i++ )
    {
       
        if( arr[ i ] == phrase[ matchCount ] )
        {
            matchCount++;
            if( matchCount ==( strlen( phrase ) ) )
            {
                count++;
                matchCount = 0; //reset matching characters number
            }
        }
        else
        {
            matchCount = 0;
        }
    }
    return count;
}
P-173951
pekfos
» 2019-02-13 20:03:17
ale niezbyt wiem dlaczego licznik i powinienem zresetować
Jak będziesz szukać "ab" w tekście "aab", to nie znajdziesz. Jak wyzerujesz matchCount z powodu błędnego znaku, to musisz odpowiednio cofnąć i.

C/C++
for( i = 0; i <( fileLen - strlen( phrase ) + 1 ); i++ )
Pętla powinna przechodzić po całej tablicy.
P-173952
tirurir
Temat założony przez niniejszego użytkownika
» 2019-02-13 20:28:31
Pętla... racja, początkowo uznałem, że jeśli fraza ma 5 znaków to nie ma po co ostatnich trzech sprawdzać ale miałem tu na myśli początek frazy i zapomniałem o jej początku.

Błąd który opisałeś (tekst ="aab", fraza = "ab") co prawda rozpisuje się tak:
tekst [0] = "a"   matchCount = 1
tekst [1] = "a"   matchCount = 0
tekst [2] = "b"   matchCount = 0

Dodanie do dolnego elsa "i--" spowoduje pętle więc utworzyłem warunek który zadziała tylko gdy matchCount nie równał się zero (czyli wcześniejszy znak pasował) ale to niestety nie wystarcza.
C/C++
int search( char arr[], int fileLen, char phrase[] ) //count all occurances of the phrase in arr
{
    int i, matchCount = 0; //iteration counter, matching characters counter
    int count = 0; //occarances counter
    for( i = 0; i < fileLen; i++ )
    {
       
        if( arr[ i ] == phrase[ matchCount ] )
        {
            matchCount++;
            if( matchCount ==( strlen( phrase ) ) )
            {
                count++;
                matchCount = 0; //reset matching characters number
            }
           
        }
        else
        {
            if( matchCount != 0 ) i--;
           
            matchCount = 0; //reset matchCount if characters don't match
        }
    }
    return count;
}
P-173954
jankowalski25
» 2019-02-13 20:35:51
warunek który zadziała tylko gdy matchCount nie równał się zero
C/C++
if( matchCount != 0 ) i--;

matchCount = 0; //reset matchCount if characters don't match
Nie. Taki kod spowoduje, że matchCount zawsze będzie równe zero.
P-173956
tirurir
Temat założony przez niniejszego użytkownika
» 2019-02-13 20:46:13
Chyba za szybko staram się to poprawić, a za mało już dostrzegam. Kolejna poprawka spowodowała pętlę. Możliwe, że wrócę do tego jutro ze świeżym okiem.
C/C++
int search( char arr[], int fileLen, char phrase[] ) //count all occurances of the phrase in arr
{
    int i, matchCount = 0; //iteration counter, matching characters counter
    int count = 0; //occarances counter
    for( i = 0; i < fileLen; i++ )
    {
        //    printf("arr[]=%c phrase[]=%c i=%d matchCount=%d\n",arr[i], phrase[i], i, matchCount); //TEST
        if( arr[ i ] == phrase[ matchCount ] )
        {
            matchCount++;
            if( matchCount ==( strlen( phrase ) ) )
            {
                count++;
                matchCount = 0; //reset matching characters number
            }
           
        }
        else
        {
            if( matchCount != 0 )
            {
                i--;
            }
            else
            {
                matchCount = 0; //reset matchCount if characters don't match
            }
        }
    }
    return count;
}
P-173957
jankowalski25
» 2019-02-13 20:53:45
C/C++
else
{
    matchCount = 0; //reset matchCount if characters don't match
}
Ten kawałek kodu nie robi nic. Równie dobrze mogłoby go nie być.

Chyba moja poprzednia odpowiedź nie była zbyt trafna. Chodzi o to, że jeśli już zerujesz matchCount, to musisz odpowiednio cofnąć i (czyli niekoniecznie o jeden). Rozważ przypadek szukania
"ababac"
 wewnątrz
"abababac"
.
P-173958
« 1 » 2
  Strona 1 z 2 Następna strona