Fscanf en C++

Résolu/Fermé
Myrne - 15 mai 2008 à 01:00
 Pumbaa - 16 mai 2008 à 09:11
Bonjour,
Je suis actuellement en train de regarder une série, et les sous titres de celle-ci sont complètement décalés. J'ai voulu les modifier tous d'un coup au moyen d'un petit programme, mais je me débats avec la fonction fscanf et je n'arrive à rien.

voilà le format des fichiers de sous titre :

1
00:00:01,656 --> 00:00:03,503
Okay where were we?

2
00:00:03,503 --> 00:00:05,450
It was June of 2006,

3
00:00:05,450 --> 00:00:07,747
and life had just taken
an unexpected turn.



and so on...


et voilà le bout de programme que j'ai commencé, et qui ne marche pas aussi bien que je l'aurai souhaité...

typedef struct
{
	int numero;
	int heure;
	char ponct1[2];
	int min;
	char ponct2[2];
	int sec;
	char ponct3[2];
	int cent;
	char texte[256];
} soustitre;

FILE *fich1,*fich2;
soustitre sbt;

void main()
{
	fich1=fopen("How I Met Your Mother - 02x01 - Where were we.xvid.srt","rt");
	fich2=fopen("sous titre.srt","wt");
	while(!feof(fich1))
	{

		fscanf(fich1,"%d \n",sbt.numero);
		fprintf(fich2,"%d \n",sbt.numero);
		
		fscanf(fich1,"%d",sbt.heure);
		fprintf(fich2,"%d",sbt.heure);

		fscanf(fich1,"%s",sbt.ponct1);
		fprintf(fich2,"%s",sbt.ponct1);

		fscanf(fich1,"%d",sbt.min);
		fprintf(fich2,"%d",sbt.min);

		fscanf(fich1,"%s",sbt.ponct2);
		fprintf(fich2,"%s",sbt.ponct2);

		fscanf(fich1,"%d",sbt.sec);
		fprintf(fich2,"%d",sbt.sec);

		fscanf(fich1,"%s",sbt.ponct3);
		fprintf(fich2,"%s",sbt.ponct3);

		fscanf(fich1,"%d \n",sbt.cent);
		fprintf(fich2,"%d \n",sbt.cent);

		fscanf(fich1,"%s \n",sbt.texte);
		fprintf(fich2,"%s \n",sbt.texte);
	}
}




Je sais, pour l'instant je ne modifie rien, mais c'était simplement pour voir si ça marchait, et manifestement ça ne marche pas. Avec le débuggeur, je peux voir que la première lecture fonctionne (le numéro du sous titre), mais les suivantes non. Pourrait-t'on m'expliquer le fonctionnement de cette fonction fscanf ?

Sinon, je voudrais juste confirmation (ou infirmation) : il me semble que les espaces séparent les strings, et que donc dans mon sous titre n°1, j'ai en fait 4 strings. C'est bien ça ? Et pour éviter ce problème, c'est bien "%[^\n]s" que je suis censé utiliser ?

Enfin dernière question, des fois les sous titres font deux lignes, et d'autres fois une ligne, ya moyen d'adapter ça lors de la lecture du fichier ? Parce ce que je fais pour le moment, c'est pour les fois, peu nombreuses mais néanmoins présentes, où il n'y a qu'une seule ligne de sous titre.



Je sais, je me complique la vie pour pas grand chose, je pourrais télécharger des sous titres un peu mieux timés, mais ce serait nettement moins intéressant. Et qui plus est, ça me servira pour mon oral dans un mois ^^''

Merci d'avance

10 réponses

Très bien. Alors bravo à toi pour avoir atteint ton but ^^
1
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
15 mai 2008 à 08:51
Salut.
beaucoup à dire.
Déjà, c'est du C++, d'après le titre, donc autant utiliser ses avantages. Déclare ta structure comme un objet :
struct soustitre
{
	int numero;
	int heure;
	char ponct1[2];
	int min;
	char ponct2[2];
	int sec;
	char ponct3[2];
	int cent;
	char texte[256];
} ;
ensuite, pour les scanf, je ne suis pas un pro, regarde sur google ou sur un shell Unix "man scanf" pour avoir plus de détails sur la fonction. Tu peux aussi utiliser std::cin.

fprintf(fich2,"%d",sbt.heure);
est incompatible avec :
00:00:03,503 --> 00:00:05,450
à mon avis, ça doit mettre 0 dans ton heure. car ':', '-->' et ',' sont vue comme ne fesant pas partie du champ entier numérique, mais comme des caractères. à la rigueur pour la virgule, tu peux t'en sortir en utilisant la localisation française.

Pour ta question de etour à la ligne : je ne sais pas.

Enfin dernière question, des fois les sous titres font deux lignes, et d'autres fois une ligne, ya moyen d'adapter ça lors de la lecture du fichier ? Parce ce que je fais pour le moment, c'est pour les fois, peu nombreuses mais néanmoins présentes, où il n'y a qu'une seule ligne de sous titre.
détecte les ligne vide : c'est a dire lit et concatène ta chaine jusqu'à avoir une ligne vide.
0
Mahmah Messages postés 496 Date d'inscription lundi 17 septembre 2007 Statut Membre Dernière intervention 22 juin 2010 125
15 mai 2008 à 10:50
Salutations,

Déclare ta structure comme un objet
Je sais je suis tatillon, une structure est un type. Un objet est une instance d'un type.

J'ai une première question/suggestion. Pourquoi ne pas demander à ton lecteur de décaler les sous-titres ?
Certes, c'est moins "fun".. ^^"

Je viens juste de voir en passant un coup sur le code, les résultat des fopen ne sont pas vérifiés.

Je changerais la structure : Un sous-titre est caractérisé par un numéro, une date d'affichage, une date de retrait de l'affichage et un texte. J'en ferais donc une structure avec unsigned int numero; Date debut; Date fin; char texte[256];
Les Date contiendront quatre unsigned int.

D'après la doc que j'ai vue le type du scanf serait "%[^\n]" sans le 's'

Pour les dates on peut aussi essayer un :
scanf( "%u:%u:%u,%u --> %u:%u:%u,%u",
            &st.debut.heure, &st.debut.min, &st.debut.sec, &st.debut.cent,
            &st.fin.heure, &st.fin.min, &st.fin.sec, &st.fin.cent );


Pour le texte, l'idée est de lire et de concaténer les lectures jusqu'à une ligne blanche.
st.texte[0] = '\0';

while ( ( fscanf( pFile, "%[^\n]", tampon ) == 1 ) && ( *tampon != '\0' ) )
    strncat( st.texte, tampon ... ;

if ( *tampon != '\0' )
    // Arrêter le programme : Erreur de lecture ! (afficher le numéro de sous titre etc.)

mais c'est à vérifier et à compléter.
Je ne sais pas si on peut mettre un fscanf( pFile, "%256[^\n]", st.texte ) mais ça serait plus classe.

A tester aussi, remplacer la boucle par :
fscanf( pFile, "%256[^\n]\n", st.texte ) == 1

Pour tenter de le forcer scanf à prendre tous les caractères jusqu'à deux retours chariots successifs.

Je te laisse le soin de vérifier tout ce que j'ai pu dire ^^"

M.
0
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
15 mai 2008 à 13:38
Ouai, je voulais dire comme pour une programmation orienté objet, et pas comme un type C.
Bonne idée la modification de la lecture de l'heure. par contre, je ne suis pas persuadé par ta modification de boucle, sinon, comment faire un fprintf() avec rien ?
pour l'instruction : while ( ( fscanf( pFile, "%[^\n]", tampon ) == 1 ) && ( *tampon != '\0' ) )
est tu sur que *tampon!=0 sera évalué après le fscanf() ?
Bonne chance
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Bon, voilà ou j'en suis :

Bravo et merci Mahmah pour la lecture de l'heure, ça marche parfaitement. Me reste le problème de la lecture du texte. Je m'y connais pas assez en programmation pour comprendre parfaitement ce que tu fais, donc euh, pourrais tu me dire si j'ai bien compris ?

st.texte[0] = '\0';

while ( ( fscanf( pFile, "%[^\n]", tampon ) == 1 ) && ( *tampon != '\0' ) )
    strncat( st.texte, tampon ... ;

if ( *tampon != '\0' )
    // Arrêter le programme : Erreur de lecture ! (afficher le numéro de sous titre etc.)



le fscanf renvoie 1 quand il a réussi à lire ce qu'on lui demandait ?
à supposer que ce soit ça, on fait bien : "tant qu'on arrive à lire ce qui est demandé (que l'on enregistre dans tampon) et tant qu'il y a quelque chose dans tampon, on concatène tampon à st.texte" ?
Et tampon sera vide lorsqu'il y aura un retour chariot sans texte avant, et donc normalement on aura récupéré toutes les lignes de texte.

Mais ça doit pas être ça parce que ça ne marche pas.

Voila ce que j'ai au départ comme fichier de sous titres, et ce que je récupère après :

1
00:00:01,656 --> 00:00:03,503
Okay where were we?

2
00:00:03,503 --> 00:00:05,450
It was June of 2006,

3
00:00:05,450 --> 00:00:07,747
and life had just taken
an unexpected turn.


Ce que je récupère :


0:0:1,656 --> 0:0:3,503
Okay where were we?

2 
0:0:3,503 --> 0:0:5,450
It was June of 2006,

3 
0:0:5,450 --> 0:0:7,747
and life had just taken

3 
0:0:5,450 --> 0:0:7,747
an unexpected turn.


Je n'arrive pas à comprendre pourquoi la ligne du numéro et celle de l'heure s'écrit deux fois. Une fois pour chaque ligne de sous titre.

Voilà mon bout de code :

void main()
{
	fich1=fopen("How I Met Your Mother - 02x01 - Where were we.xvid.srt","rt");
	fich2=fopen("sous titre.srt","wt");
	while(!feof(fich1))
	{

		fscanf(fich1,"%u \n",&st.numero);
		fprintf(fich2,"%u \n",st.numero);
		
		fscanf(fich1,"%u:%u:%u,%u --> %u:%u:%u,%u\n",&st.debut_heure, &st.debut_min, &st.debut_sec, &st.debut_cent,&st.fin_heure, &st.fin_min, &st.fin_sec, &st.fin_cent );
		fprintf(fich2,"%u:%u:%u,%u --> %u:%u:%u,%u\n",st.debut_heure, st.debut_min, st.debut_sec, st.debut_cent,st.fin_heure, st.fin_min, st.fin_sec, st.fin_cent );

		st.texte1[0] = '\0';
		while ( ( fscanf(fich1, "%[^\n]s", tampon ) == 1 ) && ( *tampon != '\0' ) )
		{
			strcat(st.texte,tampon);
		}
		fprintf(fich2,"%s\n\n",st.texte);

	}
}
0
Mahmah Messages postés 496 Date d'inscription lundi 17 septembre 2007 Statut Membre Dernière intervention 22 juin 2010 125
15 mai 2008 à 15:40
Je n'ai pas comrpris le sinon, comment faire un fprintf() avec rien ?

Dans while ( ( fscanf( pFile, "%[^\n]", tampon ) == 1 ) && ( *tampon != '\0' ) ) le ( *tampon != '\0' ) est évalué après fscanf et seulement si le fscanf() == 1 est vrai. (Faux ET X est nécessairement faux, X n'est pas évalué)

Scanf renvoie le nombre de variables qu'il a rempli avec succès, il devrait renvoyer 8 pour les heures par exemple.

Et... oui, le but de la manœuvre est ce que tu as dit.
Pour tester ce qui cloche il faudrait afficher le contenu de tampon dans le while afin de vérifier qu'il a bien lu chaque ligne. Si il a lu la dernière il a nécessairement lu les précédentes. Je n'imagine pas que cela puisse être un problème de concaténation bien que le comportement semble l'accuser. seule la dernière ligne serait recopiée dans st.texte ? Je pense plutôt que le st.texte serait écrasé par le tampon à chaque tour mais pourquoi ?

A coup de printf on doit pouvoir voir ce qu'il se passe. avec le tampon et le texte avant et après le strcat.
Ceci dit, je ne suis pas sûr que ce soit vraiment utile d'avoir un tampon avec tout le texte dedans, il pourrait être ré-écrit à la volée (/Ligne par ligne) dans l'autre fichier comme c'est fait avec le reste.

Si le dernier s'écrit deux fois c'est à cause du while( !feof() ) Le fichier n'est pas vide car il reste au moins un \n à y lire, par contre il doit se passer des truc pas beau pendant ce dernier tour de boucle ^^" On pourrait le détecter par exemple quand le scanf du numéro de ligne échoue...

M.
0
En fait, le dernier s'ecrit pas vraiment deux fois, le numero et les heures ne changent pas, mais le texte changent. Ca n'apparait que quand il y a deux lignes de texte. Et en réalité le fichier de sous titres possede environ 500 textes, et le dernier tour de boucle ne semble pas poser de probleme.
Je vais tenter de voir ce qui se lit, mais la réécriture à la volée, j'y étais pas arrivé la fois d'avant.
0
Mahmah Messages postés 496 Date d'inscription lundi 17 septembre 2007 Statut Membre Dernière intervention 22 juin 2010 125
15 mai 2008 à 16:47
Ah oui, pardon, je n'avais pas vu que c'était les deux lignes du même texte ^^"

Ce qui se passe à coup sûr alors c'est que le while qui fait le scanf ne boucle jamais comme il devrait.

La première ligne de texte est lue, le while ne boucle pas, on affiche la ligne.
La boucle principale refait un tour. Elle essaie de lire un numéro mais comme on en est toujours à la deuxième ligne de texte, le scanf échoue ssur le numéro (il retourne 0), les dates échouent aussi et donc tous ces champs ne sont pas modifiés par rapport à la dernière lecture. D'où le même numéro et les mêmes dates. Seule la lecture de la ligne de texte réussit. Ca expliquerait tout ce qui se produit. Cette théorie me plaît.

Conclusion, je me suis gouré dans mes conditions du while ^^"
(Je crois même que c'est ce qu'on essayait de me dire plus haut)

M.
0
Salut.

Si tu programmes pour t'occuper pendant les vacances, c'est très bien je ne peux que t'y encourager ! Par contre, il existe déjà de nombreux programme pour décaler les sous-titre.
Perso, j'utilise BS-Player qui est un lecteur vidéo avec sous-titre intégré qui permet de décaler provisoirement les sous-titres en cours. C'est à dire que le fichier de sous-titre n'est pas modifié.
0
Bon bah avec ce que tu m'as expliqué pour l'écriture en double des numéros et heures, j'ai réussi a faire la lecture et la réécriture jusqu'au bout. Me reste à faire un décalage, mais ça je ne me fais aucun soucis, j'y arriverai ^^

Merci beaucoup à tous le monde, et particulièrement à Mahmah. Si ce dessous, mon programme, la méthode de contournement de la double écriture est pas très élégante, mais elle marche et ça me suffit :-)

while(!feof(fich1))
	{

		fscanf(fich1,"%u \n",&st.numero);
		if (st.numero!=numero0) {fprintf(fich2,"\n%u \n",st.numero);}
		numero0=st.numero;
		
		fscanf(fich1,"%u:%u:%u,%u --> %u:%u:%u,%u\n",&st.debut_heure, &st.debut_min, &st.debut_sec, &st.debut_cent,&st.fin_heure, &st.fin_min, &st.fin_sec, &st.fin_cent );
		if (st.debut_heure!=100) {fprintf(fich2,"%u:%u:%u,%u --> %u:%u:%u,%u\n",st.debut_heure, st.debut_min, st.debut_sec, st.debut_cent,st.fin_heure, st.fin_min, st.fin_sec, st.fin_cent );}
		st.debut_heure=100;

		fscanf(fich1, "%[^\n]s", st.texte );
		fprintf(fich2,"%s\n",st.texte);
		st.texte[0] = '\0';
	}



@Pumbaa : Je sais bien que de tels logiciels existent, mais je l'ai précisé au début, c'était par simple intérêt pour la chose. Qui plus est, j'ai fini la série sans les sous-titres juste après avoir posté ce topic.
0