Jump to content

SUBIECTE NOI
« 1 / 5 »
RSS
Magnet in loc de clește pent...

Cumparat/Locuit in apartament si ...

Pot folosi sistemul PC pe post de...

Sokol cu distorsiuni de cross-over
 Filtru apa potabila cu osmoza inv...

Kanal D va difuza serialul “...

Upgrade xiaomi mi11

securitate - acum se dau drept - ...
 Farmacia Dr Max - Pareri / Sugest...

De unde cumparati suspensii / gar...

[UNDE] Reconditionare obiecte lemn

Infiltratii casa noua
 sugestie usa interior

ANAF si plata la selfpay

Imprimanta ciss rezista perioade ...

Garmin fēnix 7 / PRO / Saphi...
 

Împărțirea șirurilor de caractere – teorie + practica = ❤️

- - - - -
  • Please log in to reply
2 replies to this topic

#1
dani.user

dani.user

    Guru Member

  • Grup: Senior Members
  • Posts: 30,235
  • Înscris: 24.02.2007

Quote

Sa se afiseze doar cuvintele dintr-un sir de caractere care...

Suna cunoscut? Mai mult ca sigur. Problema impartirii sirurilor de caractere dupa anumiti separatori este una foarte des intalnita atat in probleme scolare cat si in practica.

Simpla la prima vedere, problema vine insa cu o provocare ascunsa, provocare adesea constientizata abia cand se incepe implementarea: ce returnam?

  • Un vector de siruri de caractere mai mici? Cate? Trebuie determinat. Cine aloca/dezaloca memoria? Copiem sirul sau returnam doar pointeri din sirul initial?
  • Cate un sir odata precum strtok? Unde pastram starea intre apeluri?
  • Ce facem daca avem doi separatori succesivi? Ignoram sau returnam un sir gol?

Eh... cam multe intrebari.

Abordarea prezentata mai jos va fi una cu accent mai mare pe functii, si-l va ajuta pe cititor sa inteleaga mai bine urmatoarele:

  • Lucrul cu pointeri
  • Lucrul cu functii
  • Separarea codului pentru a fi mai usor de inteles ce face fiecare bucata
  • Refactoring - modernizarea treptata a codului

Ce se cere?

Dat fiind sirul "Are Ana mere? Da!" sa extragem cuvintele: "Are", "Ana", "mere", "Da".

Cum obtinem asta?

Algoritmul e simplu: iteram prin caracterele ce compun sirul iar cat timp avem o litera, inca nu s-a terminat cuvantul curent; cand dam de un separator (spatiu, semn de punctuatie, etc) stim ca e gata cuvantul precedent iar ce urmeaza va face parte din alt cuvant.

Pasul 1 – Cum transmitem datele de intrare?

In C, sirul de caractere e deobicei un vector de caractere asezate unul dupa altul in memorie, si cu valoarea 0 in final. Acea valoare 0 indica finalul sirului. Fara ea n-am stii cat de mult se intinde sirul in memorie (ar fi fost nevoie sa pastram separat dimensiunea).

Attached File  Untitled.png   17.41K   7 downloads

Pasul 2 – Cum izolam cuvintele?

Iteram o singura data prin sir, si pastram un contor suplimentar. Consideram, deocamdata, caracterele ' ', '?' si '!' drept separatori. In cod am folosit termenul segment, mai generic decat cuvant.

void imparteSirul(const char* sir)
{
	unsigned int startSegment = 0, i = 0;
	for (i = 0; sir[i] != 0; ++i)
	{
		if (sir[i] == ' ' || sir[i] == '?' || sir[i] == '!')
		{
			unsigned int lungimeSegmentCurent = i - startSegment;
			if (lungimeSegmentCurent > 0)
			{
				const char* segment = sir + startSegment;
				//fa ceva cu segmentul gasit
			}
			startSegment = i + 1;
		}
	}
}

int main()
{
	imparteSirul("Are Ana mere? Da!");
}


Pasul 3 – Ce facem cu rezultatele gasite?

Ce facem cu fiecare cuvant/segment gasit? Hai sa-l dam inapoi celui ce ne-a cerut. Cum? Folosind un callback, codul ce ne cere sa impartim sirul ne va oferi si o functie pe care o vom apela pentru fiecare cuvant gasit. Functia va primi doua argument:

  • Un pointer din sirul initial, indicand unde incepe sirul
  • Lungimea cuvantului curent (nu ne mai putem baza pe 0'ul de la final deoarece la finalul sirului initial, nu la finalul fiecarui cuvant)

Functia respectiva poate face orice cu fiecare cuvant:

#include <stdio.h>

typedef void(*PrimesteUnSegment)(const char* sir, unsigned int lungime);

void afiseazaSegmentul(const char* sir, unsigned int lungime)
{
	printf("Am primit un nou segment de lungime %d: ", lungime);

	for (unsigned int i = 0; i < lungime; ++i)
	{
		printf("%c", sir[i]);
	}

	printf("\n");
}

void imparteSirul(const char* sir, PrimesteUnSegment daSegmentulMaiDeparte)
{
	unsigned int startSegment = 0, i = 0;
	for (i = 0; sir[i] != 0; ++i)
	{
		if (sir[i] == ' ' || sir[i] == '?' || sir[i] == '!')
		{
			unsigned int lungimeSegmentCurent = i - startSegment;
			if (lungimeSegmentCurent > 0)
			{
				const char* segment = sir + startSegment;
				daSegmentulMaiDeparte(segment, lungimeSegmentCurent);
			}
			startSegment = i + 1;
		}
	}
	//daca sirul nu se termina cu un separator, sa nu uitam de ultimul segment
	unsigned int lungimeSegmentCurent = i - startSegment;
	if (lungimeSegmentCurent > 0)
	{
		const char* segment = sir + startSegment;
		daSegmentulMaiDeparte(segment, lungimeSegmentCurent);
	}
}

int main()
{
	imparteSirul("Are Ana mere? Da!", afiseazaSegmentul);
}


Quote

Am primit un nou segment de lungime 3: Are
Am primit un nou segment de lungime 3: Ana
Am primit un nou segment de lungime 4: mere
Am primit un nou segment de lungime 2: Da

Pasul 4 – Daca vrem sa folosim si alti separatori?

Cele 3 caractere alese drept separatori sunt suficiente pentru exemplul curent, dar nu sunt suficiente. Ce putem face pentru a generaliza si mai mult solutia? Cerem celui ce ne apeleaza inca o functie, o functie pe care o vom apela pentru fiecare caracter pentru a afla daca sa-l tratam ca un separator sau nu.

In codul de mai jos, orice caracter ce nu e o litera mica sau mare (ASCII) e considerat un separator.

#include <stdio.h>

typedef void(*PrimesteUnSegment)(const char* sir, unsigned int lungime);
typedef int(*DeterminareLungimeSeparator)(const char* sir);

void afiseazaSegmentul(const char* sir, unsigned int lungime)
{
	printf("Am primit un nou segment de lungime %d: ", lungime);

	for (unsigned int i = 0; i < lungime; ++i)
	{
		printf("%c", sir[i]);
	}

	printf("\n");
}

int determinareLungimeSeparatorLitere(const char* sir)
{
	return (*sir >= 'a' && *sir <= 'z') || (*sir >= 'A' && *sir <= 'Z') ? 0 : 1;
}

void imparteSirul(const char* sir, PrimesteUnSegment daSegmentulMaiDeparte, DeterminareLungimeSeparator catESeparatorulDeLung)
{
	unsigned int startSegment = 0, i = 0;
	for (i = 0; sir[i] != 0; ++i)
	{
		int lungimeSeparator = catESeparatorulDeLung(sir + i);
		if (lungimeSeparator > 0)
		{
			unsigned int lungimeSegmentCurent = i - startSegment;
			if (lungimeSegmentCurent > 0)
			{
				const char* segment = sir + startSegment;
				daSegmentulMaiDeparte(segment, lungimeSegmentCurent);
			}
			i += (lungimeSeparator - 1);
			startSegment = i + 1;
		}
	}
	//daca sirul nu se termina cu un separator, sa nu uitam de ultimul segment
	unsigned int lungimeSegmentCurent = i - startSegment;
	if (lungimeSegmentCurent > 0)
	{
		const char* segment = sir + startSegment;
		daSegmentulMaiDeparte(segment, lungimeSegmentCurent);
	}
}

int main()
{
	imparteSirul("Are Ana mere? Da!", afiseazaSegmentul, determinareLungimeSeparatorLitere);
}


Quote

De ce soliciti lungimea separatorului si nu doar daca e prezent sau nu?

Deoarece un separator poate avea mai mult de o litera. In acest caz e nevoie de lungimea separatorului gasit pentru a stii peste cate caractere sa sarim.

De exemplu, putem avea "A<>B<>C" ce se vrea impartit dupa separatorul "<>".

int separatorComplex(const char* sir)
{
	return (sir[0] == '<' && sir[1] == '>') ? 2 : 0;
}

int main()
{
	imparteSirul("A<>B<>C", afiseazaSegmentul, separatorComplex);
}


Quote

Am primit un nou segment de lungime 1: A
Am primit un nou segment de lungime 1: B
Am primit un nou segment de lungime 1: C

Tema de casa

Cum ne poata ajuta C++ sa scriem codul mai generic?

Edited by dani.user, 06 December 2017 - 21:53.


#2
VladBtz

VladBtz

    Active Member

  • Grup: Members
  • Posts: 1,702
  • Înscris: 24.09.2014
se pot folosi si bibliotecile string si cstring

#3
dani.user

dani.user

    Guru Member

  • Grup: Senior Members
  • Posts: 30,235
  • Înscris: 24.02.2007
Biblioteci sunt multe, considerabil mai bune decat strtok din cstring.

Anunturi

Bun venit pe Forumul Softpedia!

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

Forumul Softpedia foloseste "cookies" pentru a imbunatati experienta utilizatorilor Accept
Pentru detalii si optiuni legate de cookies si datele personale, consultati Politica de utilizare cookies si Politica de confidentialitate