IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

PArse d'un fichier ligne par ligne qui match plusieurs pattern


Sujet :

C++

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    360
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 360
    Points : 137
    Points
    137
    Par défaut PArse d'un fichier ligne par ligne qui match plusieurs pattern
    Bonjour,

    Je souhaiterais parser un fichier ligne par ligne et recupérer chaque ligne de ce fichier qui contient deux pattern.

    par exemple si j'ai le fichier suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    mot1 mot2 mot3 mot4
    mot5 mot2 mot6 mot3
    mot2 mot8 mot9 mot3
    ...
    en sortie dans un vector de structure j'imagine, j'aimerais récupérer les infos suivantes par rapport au fichier.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    mot2 mot3 //de la premiere ligne
    mot2 mot3 //dela deuxiemen ligne
    mot2 mot3  //de la troisieme ligne
    ...
    le résultat se trouvait dans un vector:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    struct mots
    {
     std::string _mot1;
     std::string _mot2;
    }
     
    std::vector<mots> _vectMot;
    C'est faisable en c/c++ en utilisant les strstr, strncpy, strcpy mais c'est trop lourd, le fichier fait environ 2Mo.

    J'utilise visual studio 2013 sous windows x64, je pensait utiliser boost, qui doit le faire en quelques lignes.

    boost récupérerait directement dans un vector la ligne qui match les deux patterns.

    Ou bien spliter le fichier ligne par ligne dans un vector et faire un strstr, mais pas terrible.

    par exemple dans le code suivant je recupere dans buffer la ligne qui correspond a un mot se trouvant ds la variable m_szFilter, je trouve le code un peu pourri:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
     
    	if ((filename == NULL) || ((int)strlen(filename) == 0)) return false;
     
    	char *BufFile = NULL;
    	HANDLE hFile;
    	ULONG numread;
    	ULONG nLen = 0;
    	TCHAR szLineFilter[TEXTBUFSIZE];
     
    	hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
     
    	if(hFile == INVALID_HANDLE_VALUE)
    	{		
    		return false;
    	}
     
    	if((nLen = GetFileSize(hFile, 0)) == 0)
    	{
    		CloseHandle(hFile);
    		return false;	
    	}
     
    	if((BufFile = new char[nLen+1]) == 0)
    	{
    		CloseHandle(hFile);
    		return false;	
    	}	
     
    	if((buffer = new char[nLen+1]) == 0)
    	{
    		CloseHandle(hFile);
    		return false;	
    	}
     
    	ReadFile(hFile, BufFile, nLen, &numread, 0);	
    	BufFile[nLen] = '\0';
     
    	ULONG nLine = 0;
    	ULONG nCurIndex = 0;
    	ULONG nPos = 0;
    	ULONG i;
    	ULONG nTotalBytes = 0;
    	ULONG nRead = 0;
     
    	for(i = 0; i < nLen; )
    	{
    		if(BufFile[i] == '\r') //Next line
    		{
    			// carriage-return / line-feed combination
    			if(BufFile[i+1] == '\n')
    				i++;
     
    			nLine = ++i; //Index next line			
     
    			strncpy_s(szLineFilter, TEXTBUFSIZE, &BufFile[nCurIndex], nLine - nCurIndex);
    			if (strstr(szLineFilter, m_szFilter)) //Filter found
    			{				
    				nRead = nLine - nCurIndex;
    				memcpy(buffer + nTotalBytes, szLineFilter, nRead);
    				nTotalBytes += nRead;
    				nCurIndex = nLine;
    			} else nCurIndex = nLine;						
    		}
    		else if(BufFile[i] == '\n') //Next line
    		{
    			nLine = ++i;	
     
    			strncpy_s(szLineFilter, TEXTBUFSIZE, &BufFile[nCurIndex], nLine - nCurIndex);
    			if (strstr(szLineFilter, m_szFilter)) //Filter found
    			{				
    				nRead = nLine - nCurIndex;
    				memcpy(buffer + nTotalBytes, szLineFilter, nRead);
    				nTotalBytes += nRead;
    				nCurIndex = nLine;
    			} else nCurIndex = nLine;			
    		}
    		else
    		{
    			i++;
    		}
     
    		if(i >= nLen) //Last read
    		{
    			nLine = i;			
    			strncpy_s(szLineFilter, TEXTBUFSIZE, &BufFile[nCurIndex], nLine - nCurIndex);
    			if (strstr(szLineFilter, m_szFilter)) //Filter found
    			{				
    				nRead = nLine - nCurIndex;
    				memcpy(buffer + nTotalBytes, szLineFilter, nRead);	
    				nTotalBytes += nRead;
    			} 		
    		}
     
    	}
     
    	buffer[nTotalBytes] = '\0';	
    	length = (ULONG)strlen(buffer);
     
    	CloseHandle(hFile);	
    	delete[] BufFile;
    	BufFile = 0;
    je pense toujours qu'avec boost, des ifstream ou des osstream ca doit etre faisable. j'utilise deja boost pour les regex uniquement.

    si quelqu'un aurait une piste ou une idee avec boost.

    Merci de votre aide.

  2. #2
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Boost String Algorithm est ton ami.

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    360
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 360
    Points : 137
    Points
    137
    Par défaut
    j'ai regarde la librairie de plus pres, peut etre qu'avec un split combiné avec des regex ca devrait etre possible.

  4. #4
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Hello,

    un peu de mal à comprendre l'algo, avec ce fichier
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    a b c d
    a a a a
    b b b b
    c c c c
    b a c d
    a a b b
    En recherchant "a" et "b", le résultat doit être ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    "a", "b"
    "a", "a" ou "a", "" ?
    "b", "b" ou "", "b" ou "b", "" ?
    "", "" ici j'imagine
    "a", "b" ou "b", "a" ou "", "" ?
    "a", "a" ou "a", "b" ?
    Il y à bien un élément ajouté au vector par ligne du fichier ?

  5. #5
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    360
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 360
    Points : 137
    Points
    137
    Par défaut
    en fait le fichier est un fichier de log qui contient une ip et un id, et je voulais recuperer les lignes qui conenait l'ip et l'id uniquement, en m'aidant avec le lien de oodini j'ai reduit le code a cela:

    bufferInfos contient le fichier dans un buffer, je split le fichier par ligne (\n\r) et a l'aide des regex boost je recherche mes deux patterns pour chaque ligne, une fois trouvees j'ajoute la ligne dans un vector.
    c'est deja mieux par rapport au code precedents que j'avais posté vaec des strstr, strncpy etc..: IS_MATCH est une macro de regex.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    _bufferInfos = (*_ppEditView)->getBufferDoc();
     
    	_bufferLine.clear();
    	_usersinfos.clear();
     
    	boost::regex ip("\\(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\)");
    	boost::regex id("\\[([0-9a-fA-F]){16}:([0-9a-fA-F]){4}\\]");
     
    	std::vector<std::string> SplitVect;
    	ChatRegex::splitVector(SplitVect, _bufferInfos, "\r\n");
     
    	for (int i = 0; i < SplitVect.size(); i++)
    	{
    		if (IS_MATCH(SplitVect[i].c_str())) 
    		{
    			_bufferLine.push_back(SplitVect[i].c_str());
    		}
    	}
    Maintenant mon but est de mettre l'ip et l'id dans un vecteur separer pour que je puisse les mettre dans un listview, je pense creer une structure avec deux element de type vector et le tour est joué.

    Je pense meme que les 4 lignes de code du for(int i .. peuvent se reduire a deux lignes avec le find_all_regex mais ca a l'air compliqué.

  6. #6
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    360
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 360
    Points : 137
    Points
    137
    Par défaut
    le code final:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
     
     
    bool UserInfos::serUsersInfos()
    {	
    	_bufferInfos = (*_ppEditView)->getBufferDoc();	
    	_usersinfos.clear();
     
    	boost::regex ip("\\(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\)");
    	boost::regex id("\\[([0-9a-fA-F]){16}:([0-9a-fA-F]){4}\\]");
     
    	std::vector<std::string> SplitVect;
    	ChatRegex::splitVector(SplitVect, _bufferInfos, "\r\n");
     
    	for (int i = 0; i < SplitVect.size(); i++)
    	{
    		if (IS_MATCH(SplitVect[i].c_str())) 
    		{
    			generic_string uip = string2wstring(ChatRegex::getUserIP(SplitVect[i].c_str()), CP_ACP);
    			generic_string uid = string2wstring(ChatRegex::getUserID(SplitVect[i].c_str()), CP_ACP);
     
    			_usersinfos.push_back(InfosUsers(TEXT(""), uip, uid));
    		}
    	}
     
    	return false;
    }

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    360
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 360
    Points : 137
    Points
    137
    Par défaut
    sur 17000 lignes ca met quand meme entre 1 et 1,5 seconde

  8. #8
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Points : 4 732
    Points
    4 732
    Par défaut
    Un reserve initial (même au pif avec SplitVect.size()/2 ou pire de SplitVect.size()) sur usersinfos devrait aider... Car la, tu passes ton temps a le copier.
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 9
    Dernier message: 03/07/2014, 18h08
  2. Opération sur un fichier et lecture ligne par ligne
    Par teunniq dans le forum Shell et commandes GNU
    Réponses: 6
    Dernier message: 03/06/2014, 17h57
  3. lire fichier .txt (NOTEPAD) ligne par ligne
    Par skambram dans le forum VB.NET
    Réponses: 1
    Dernier message: 06/06/2009, 18h41
  4. lire un fichier de string ligne par ligne
    Par bilzzbenzbilz dans le forum Entrée/Sortie
    Réponses: 4
    Dernier message: 11/02/2009, 10h44

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo