Parsarea fişierului de intrare

Parsarea fişierului de intrare constă în prelucrarea fişierului ca şir de caractere şi extragerea informaţiei utile (numere întregi, flotante; cuvinte etc.) folosind proceduri proprii. Avantajul acestei metode este rapiditatea programului. Funcţiile standard pentru citire din fişier găsite în stdio.h sau iostream, fstream etc. au dezavantajul că sunt foarte generaliste, permiţând tot soiul de reguli obscure de formatare.

Atunci când vă scrieţi parsarea proprie, de obicei includeţi strictul necesar (de exemplu doar numere pozitive, de tipul int, ca la majoritatea problemelor). Mai jos aveţi două bucăţi de cod demonstrative (pentru C şi C++), care se concentrează pe:

  • citirea unui caracter
  • citirea unui număr întreg de tip int, fie el şi negativ (puteţi tăia partea cu semnul '-' dacă nu aveţi nevoie)
  • citirea unui număr întreg de tip long long, fie el şi negativ

Pentru parsarea fişierului de ieşire, urmaţi linkul http://www.infoarena.ro/parsare-fisier-iesire

Cod compatibil cu limbajul C++ şi sintaxa <fstream> (obiectual)

Acesta este un cod demonstrativ pentru parsarea fişierului de intrare folosind metoda obiectuală:

#include <stdio.h>
#include <ctype.h>

class InParser {
private:
	FILE *fin;
	char *buff;
	int sp;

	char read_ch() {
		++sp;
		if (sp == 4096) {
			sp = 0;
			fread(buff, 1, 4096, fin);
		}
		return buff[sp];
	}

public:
	InParser(const char* nume) {
		fin = fopen(nume, "r");
		buff = new char[4096]();
		sp = 4095;
	}
	
	InParser& operator >> (int &n) {
		char c;
		while (!isdigit(c = read_ch()) && c != '-');
		int sgn = 1;
		if (c == '-') {
			n = 0;
			sgn = -1;
		} else {
			n = c - '0';
		}
		while (isdigit(c = read_ch())) {
			n = 10 * n + c - '0';
		}
		n *= sgn;
		return *this;
	}
	
	InParser& operator >> (long long &n) {
		char c;
		n = 0;
		while (!isdigit(c = read_ch()) && c != '-');
		long long sgn = 1;
		if (c == '-') {
			n = 0;
			sgn = -1;
		} else {
			n = c - '0';
		}
		while (isdigit(c = read_ch())) {
			n = 10 * n + c - '0';
		}
		n *= sgn;
		return *this;
	}
};

Cum folosim acest cod?

Aveţi mai jos un exemplu de utilizare al clasei. Puteţi observa asemanarea între acesta şi clasele din fstream. Singura diferenţă notabilă este că nu va putea citi decât int şi long long (şi caractere prin intermediul unei funcţii private).

int main()
{
	InParser fin("file.in");
	int a;
	long long b;
	fin >> a >> b;
	printf("%lld\n", b + a);
	return 0;
}

Cod compatibil cu limbajul C (procedural)

Acesta este un cod demonstrativ pentru parsarea fişierului de intrare folosind metoda procedurală:

#include <stdio.h>
#include <ctype.h>

/** Funcţiile necesare parsării fişierului de intrare **/
FILE *_fin;
int _in_loc; char _in_buff[4096];


void read_init(const char* nume) // Apelaţi această funcţie la începutul funcţiei <main>
{
	_fin = fopen(nume, "r");
	_in_loc = 4095;
}

char read_ch()
{
	++_in_loc;
	if (_in_loc == 4096) {
		_in_loc = 0;
		fread(_in_buff, 1, 4096, _fin);
	}
	return _in_buff[_in_loc];
}

int read_u32() // Apelaţi această funcţie pentru a citi un număr ce se încadrează în categoria <unsigned int>
{
	int u32 = 0; char c;
	while (!isdigit(c = read_ch()) && c != '-');
	int sgn = 1;
	if (c == '-') {
		sgn = -1;
	} else {
		u32 = c - '0';
	}
	while (isdigit(c = read_ch())) {
		u32 = u32 * 10 + c - '0';
	}
	return u32 * sgn;
}

long long read_u64() // Apelaţi această funcţie pentru a citi un număr ce se încadrează în categoria <unsigned long long>
{
	long long u64 = 0; char c;
	while (!isdigit(c = read_ch()) && c != '-');
	long long sgn = 1;
	if (c == '-') {
		sgn = -1;
	} else {
		u64 = c - '0';
	}
	while (isdigit(c = read_ch())) {
		u64 = u64 * 10 + c - '0';
	}
	return u64 * sgn;
}

Cum folosim acest cod?

Aveţi mai jos un exemplu de utilizare al funcţiilor anterior menţionate.

int main()
{
	read_init("file.in");
	int a = read_u32();
	long long b = read_u64();
	printf("%lld", b + a);
	return 0;
}