Wczytywanie ciągów znaków z wejścia standardowego jeśli ma określoną długość

0

Język C
Wczytuję od użytkownika string:

fgets(userline, 1000, stdin);

a następnie przetwarzam go w następujący sposób:

sscanf(userline, " %19[^,], %39[^,], %d, %49[^,], %79[^,], %d", name, surname, &num1 , field, faculty, &num2);

Jak przerobić ten kod, aby:

Jeśli nie ma name lub name dłuższy niż 20 znaków, nie czytaj name ani pozostałych zmiennych
Jeśli nie ma surname lub surname dłuższy niż 40 znaków, nie czytaj surname ani pozostałych zmiennych
itd

z góry dziękuję za wszelkie wskazówki
skrycioch

0

Moim zdaniem tak:

  1. Jeżeli sscanf w ogóle zmienia wskaźnik userline (domyślam się, ze to jest wskaźnik char*, bo w C nie ma typowego string) lub zawartość, to zrób kopię.
  2. Wczytać jeden wyraz do spacji i zachować do name.
  3. Jeżeli długość name > 20, to wczytać jeden wyraz od spacji po pierwszym wyrazie lub wczytać dwa pierwsze wyrazy, potem poszukać spację.
  4. Jeżeli długość surname > 40, to wczytać resztę, albo wczytać od początku wszystko, jak sam napisałeś.

Nie ma możliwości sprawdzenia, czy określona część danych wejściowych spełnia jakiś warunek bez wczytywania tych danych. Da się ustalić liczbę i długość wyrazów bez ich wyodrębniania, poprzez poszukiwaniu pozycji wszystkich spacji i długość całości (string przyjęty od użytkownika), jednak to zadziała w idealnym przypadku.

Jeżeli przyjmuje się założenie, że użytkownik wprowadza wyrazy rozdzielone jedną spacją i nie ma pomyłek (dwie spacje między wyrazami, spacja przed pierwszym wyrazem itp), to można wyszukać pierwszą i drugą spację w stringu odebranym od użytkownika.

Mając pozycję pierwszej i drugiej spacji, a także długość całego napisu, można ustalić istnienie i długość dwóch pierwszych wyrazów.

0

Rozumiem, że tablica ma 1000 znaków.
Po pierwszę - wczytuję od użytkownika string - w jedynym niezadeklarowanym ciągu?

To jedziesz pętlą od 0 do (dlugość - "name") (-4) żeby sprawdzić czy się mieści to imię chociaż , potem robisz if(strcmp(tablica[i],"n")==0 && strcmp(tablica[i+1],"a")==0 && strcmp(tablica[i+2],"m")==0 && strcmp(tablica[i+3],"e")==0){ /* to wtedy masz imię - możesz przekopiować od tego znalezionego miejsca w tablicy reszte do drugiej tablicy, żeby wyłuskać to imie i wyszukać "surname" i potem zrobić to samo*/} (i to zmienna do określania pozycji w tablic)

Bo potem jak przekopiujesz pozostałość to będziesz potrzebował znaleźć "surname" - i dlugosc offsetu pomiedzy poczatkiem nowej tablicy a piewszym miejscem od którego "surname" się zaczyna będzie chyba imieniem.

Ale ogólnie to struktury(wcześniej czy później na nie trafisz) warto wypełniać imieniem (pewnie na początku nie będziesz ogarniać wskaźnikiem i długoscią) - wtedy nie marnujesz pamięci.

No i przy tej metodzie spacje czy ich brak nie mają znaczenia.

0

Heh miałem polecić getline ale to posix.

Ok to jak fgets przeczyta przyjmij, że jak linijka równa niż 999 znaków ( ostatni nul ) to jest zepsuta.
Czyli największa linijka jaką możesz przeczytać powinna być z założenia błędem

Następnie idź po ciągu znaków ( stringu ) i czytaj aż trafisz na spację. Czyli isspace ( ctype.h )
Zliczasz po drodze znaki jak coś nie halo to olewasz linijkę.

Imho podejście, że jak imię za długie to zostawiamy puste jest bez sensu.

Albo dane są do d**y albo trzeba dać na nie więcej miejsca.

0

Ogólnie temat polega na przepisaniu danych do struktury:

ilosc_danych=sscanf(userline, " %19[^,], %39[^,], %d, %49[^,], %79[^,], %d",
        (*p).name,(*p).surname, &(*p).num1, (*p).field, (*p).faculty, &(*p).num2);

Przy czym taki zapis powoduje, że jeśli p.surname będzie wynosić 45 znaków, wczytane zostanie 40 znaków i komunikatu o błędzie nie będzie.
Chodzi o to, żeby był.

0

A to jakiś wyższy sport, ze musi być jednym sscanfem ?

Ja bym zrobił split (split w C czyli strtok() jest dość niewdzięczne, bo zmienia bufor wejściowy i trzeba być na to przygotowanym) i procesował if'ami do smaku.

https://www.educative.io/answers/splitting-a-string-using-strtok-in-c

Nie da się inaczej zbudować np satysfakconującego komunikatu co w danych nie gra.

0

Popatrz na to podmieniasz tam tekst zrodlowy na to co wczytales i szukany na "name" i "surname" i dzialasz

#include <iostream>
#include <string.h>
#include <stdio.h>

using namespace std;
char tekst_zrodlowy[20000];
char tekst_poszukiwany[1000];




int main()
{

int dlugosc_tekstu=0;
int dlugosc_poszukiwanego_tekstu=0;

    
for(int i=0;i<20000;i++){tekst_zrodlowy[i]=4;};
for(int i=0;i<1000;i++){tekst_poszukiwany[i]=4;};  


strcpy(tekst_zrodlowy,"name aleksaned surname jakubowski");    
strcpy(tekst_poszukiwany,"name");





cout<<"dlugosc tekstu zrodlowego "<<dlugosc_tekstu<<"\n";    
cout<<"dlugosc tekstu poszukiwanego "<<dlugosc_poszukiwanego_tekstu<<"\n";    

cout<<"szukamy ...\n\n";  



for(int i=0;i<20000;i++){if(tekst_zrodlowy[i]>30 && tekst_zrodlowy[i]<125){dlugosc_tekstu++;}}  
for(int i=0;i<1000;i++){if(tekst_poszukiwany[i]>30 && tekst_poszukiwany[i]<125){dlugosc_poszukiwanego_tekstu++;}} 

for(int i=0;i<1270-6;i++) {
    
if(tekst_zrodlowy[i]==tekst_poszukiwany[0] && tekst_zrodlowy[i+1]==tekst_poszukiwany[1] && tekst_zrodlowy[i+2]==tekst_poszukiwany[2] && tekst_zrodlowy[i+3]==tekst_poszukiwany[3] 
&& tekst_zrodlowy[i+4]==tekst_poszukiwany[4] && tekst_zrodlowy[i+5]==tekst_poszukiwany[5] )
{cout<<"'button' na pozycji    "<<i<<"\n";i+=6;}  //bo tutaj szukalem "buttona" w tekscie html
};
  



    return 0;
}

Nie wie czy nie będziesz potrzebował go przerobić (tam na początku dać sprawdzenie 4 elementów tablicy "name" i potem 7 "surname")
1270 to była dlugosc tekstu oryginalnego - zmienasz to na linijke długości jaka wczytałeś. powinno Ci pokazac numer w tablicy,
robisz to na "name" i potem "surname" i masz 2 wartosci odejmując pozycję ropoczynającą "surname" od początku tablicy +4(konca "name") masz długość imienia, odejmująć dlugosc tablicy całej od pozycji koncowej "surname" masz dlugosc pola surname.
A jak teraz patrzę, to on chyba wyszukuje wszystkie wystąpienia w tekście, nawet jak jest ich kilka i podaje pozycję każdego.
Prymitywny kod ale działał, i szanował spacje.
A jak chcesz porobić wszystko zautomatyzowane to podmieniasz 6 w tym kodzie na zmienna "dlugosc_tekstu" i powinno tez zadziałać.

0
skrycioch napisał(a):

Język C
Wczytuję od użytkownika string:

fgets(userline, 1000, stdin);

a następnie przetwarzam go w następujący sposób:

sscanf(userline, " %19[^,], %39[^,], %d, %49[^,], %79[^,], %d", name, surname, &num1 , field, faculty, &num2);

Jak przerobić ten kod, aby:

Jeśli nie ma name lub name dłuższy niż 20 znaków, nie czytaj name ani pozostałych zmiennych
Jeśli nie ma surname lub surname dłuższy niż 40 znaków, nie czytaj surname ani pozostałych zmiennych
itd

z góry dziękuję za wszelkie wskazówki
skrycioch

Możesz poprawić ten test tak by pokryć wszystkie przypadki, o które ci chodzi tak by raport o błędach (int) odpowiadał twoim potrzebom?
Wtedy będzie precyzyjnie wiadomo co chcesz osiągnąć. IMO twój kod jest dośc bliski efektowi końcowemu.

0

Możesz ewentualnie wczytać najpierw samo name i użyć specyfikatora %n - zwraca on offset, gdzie zakończono czytanie stringa. Następnie ponownie odpalić sscanf ale startując od userline + offset i wczytać samo surname, znowu z %n. Dzięki temu możesz sobie po kolei sprawdzić długości wczytanych danych i przerwać, jeśli zajdzie odpowiedni warunek.
https://en.cppreference.com/w/c/io/fscanf

1 użytkowników online, w tym zalogowanych: 0, gości: 1