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

Langage Delphi Discussion :

Création d'un analyseur syntaxique


Sujet :

Langage Delphi

  1. #1
    Membre habitué

    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    639
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 639
    Points : 167
    Points
    167
    Par défaut Création d'un analyseur syntaxique
    Bonjour,

    Je dois créer le programme suivant :

    J'ai un fichier texte avec des enregistrement.
    Je dois rejeter chaque ligne qui comporte au moins un caractère non latin.
    Les fichiers peuvent contenir des centaine de milliers de lignes.

    Existe-t-il un composant qui aiderait à exécuter cette analyse syntaxique des caractères? Un outil rapide. Ou suis-je obligé de prendre caractère par caractère et de le comparer avec tous les caractères latins pour tester s'il est valide ou non?

    Merci!

  2. #2
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    Salut,

    ... Je dois rejeter chaque ligne qui comporte au moins un caractère non latin.
    1) créer par exemple un Type ChrNonLatin : array[1..N] of Char,
    2) scruter chaque ligne à partir de son début avec une boucle à interrompre au premier if MaLigne[i]=ChrNonLatin[j] then Rejet de la ligne et passage à la ligne suivante.

    Les fichiers peuvent contenir des centaine de milliers de lignes.
    ... Peu importe : Si t'as une mem-vive-disponible suffisante tu peux charger le tout dans un TMemoryStream (rapidité maxi) ... sinon tu peux utiliser un TFileStream ou bien parcourir le fichier laissé sur disque ligne par ligne avec Readln().

    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  3. #3
    Membre confirmé

    Inscrit en
    Novembre 2002
    Messages
    744
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 744
    Points : 500
    Points
    500
    Par défaut
    salut

    Juste une idée.. j'ai pas de reponse pour les composant faisant cela.

    Si Ton texte est formaté et pas brut, tu peux peut être faire une recherche du nom de la police (avec les balises) dans la ligne courante et la comparer a une liste de police mais cela demande d'identifier tous les noms de polices latines ??.

    La méthode de lecture de contrôle de caractères semble plus sure, mais peut être pas assez rapide.
    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
     
    function CtrlChaineLatine(Lg:string):boolean;
    const ChaineLatine='abcdefghijklmnopqrstv123456789....'; // chaine de caracteres valide.
    var i:integer;
    begin
        result:=true;
        for i:=1 to length(Lg)do
        begin
            if pos(lg[i],ChaineLatine)=0 then
            begin
              result:=false;
              exit;
            end;
        end;
    end;
    tu peux aussi mixer les deux pour gagner du temps, quand dans une ligne tu tombe sur une police qui t'es inconnu, alors tu contrôle les caractères..
    Bye et bon code...

    Ce n'est pas tant l'aide de nos amis qui nous aide , mais notre confiance dans cette aide .

  4. #4
    Expert confirmé

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Leader Technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Points : 4 170
    Points
    4 170
    Par défaut
    Quoi que tu fasses, il faudra bien lire chaque caractère au moins une fois pour savoir s'il appartient au jeu de caractère que tu veux.

    Personnellement, je ferais le teste avec un tableau lookup qui indique si un caractère est correct ou non :

    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
     
    const
      CharIsOk : array[char] of boolean = (false, false, ....., true, ...... ); // A définir en fonction des caractères valides.
     
    function CtrlChaine(const s : string) : boolean;
    var p : pChar;
    begin
      if s = ''
      then result := true
      else begin
        result := true;
        p := @s[1];
        while (p^<>#0) and result do
        begin
          result := result and CharIsOk[p^];
          inc(p);
        end;
      end;
    end;
    Maintenant libre à toi de voir comment gerer la lecture des chaines à tester.

  5. #5
    Membre habitué

    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    639
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 639
    Points : 167
    Points
    167
    Par défaut
    Merci pour vos réponses,

    Franck, je ne comprends pas trop comment utiliser et définir la constante CharIsOk?
    A supposer que l'alphabet latin ne soit composé que de cinq caractères : a b c d e, comment remplirais-tu le tableau?
    Et si la ligne étudiée est celle ci : abc]ac, peux tu me montrer grossièrement comment réagit ton algorythme?

    Merci!

  6. #6
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    Re-Salut,

    je ne comprends pas trop comment utiliser et définir la constante CharIsOk?
    A supposer que l'alphabet latin ne soit composé que de cinq caractères : a b c d e, comment remplirais-tu le tableau?
    const CharIsOk : array[char] of boolean = (false, false, ....., true, ...... );

    array[char] comprend les '0..255' caractères de la table Ascii
    donc dans ton exemple des cinq caractères a b c d e, le 'a' occupe la 97ième position et les quatre autres suivent.
    Donc tu mets au début 96 fois false au début et ensuite 5 fois true (pour a b c d e) et ensuite toute une série de false couvrant la plage 102..255 c'est à dire du 'f' jusqu'à la fin.

    Les 96 false du début correspondent aux caractères qui précèdent le 'a'

    Oups, faut remplacer le 32ième false du début par true : il correspond au caractère ' ' espace.

    Le mieux serait que tu prennes une table Ascii pour choisir les caractères à fixer à true car tes lignes de texte peuvent comporter des caractères de ponctuation (,;! des majuscules etc : à toi de choisir.

    A+
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  7. #7
    Membre habitué

    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    639
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 639
    Points : 167
    Points
    167
    Par défaut
    ok, merci pour cet éclaircissement!!

  8. #8
    Expert confirmé

    Inscrit en
    Août 2006
    Messages
    3 942
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 3 942
    Points : 5 654
    Points
    5 654
    Par défaut
    Hie,

    Plutôt qu'un tableau, pourquoi ne pas utiliser un ensemble
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    type
      charSet = set of char;
     
    const
      okChars : charSet = ['a'..'e','z']; { caractères a-e, z }
    utilisation :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    ...
      {c est un catactère }
      if (c in okChars)
      then
      begin
        ...
      end;
    Ça va tout aussi vite qu'avec un tableau, et ça me paraît nettement plus clair.

    Pascal, donc Delphi disposent de base ce type fort utile, utilisons-le !!
    Si les cons volaient, il ferait nuit à midi.

  9. #9
    Membre confirmé

    Inscrit en
    Novembre 2002
    Messages
    744
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 744
    Points : 500
    Points
    500
    Par défaut
    salut ,

    Et pourquoi pas une simple chaine, et un POS sur la chaine...
    En fait quelle est la solution la plus rapide ?
    Bye et bon code...

    Ce n'est pas tant l'aide de nos amis qui nous aide , mais notre confiance dans cette aide .

  10. #10
    Expert confirmé

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Leader Technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Points : 4 170
    Points
    4 170
    Par défaut
    Citation Envoyé par droggo Voir le message
    Hie,

    Plutôt qu'un tableau, pourquoi ne pas utiliser un ensemble
    Ça va tout aussi vite qu'avec un tableau, et ça me paraît nettement plus clair.
    Ben en fait non, ce n'est pas aussi rapide qu'avec un tableau. Le type ensemble est implémenté sous la forme d'un tableau de bits packé à l'intérieur d'un entier.
    Pour tester si un élément fait parti de l'ensemble, il faut identifier le numéro du bit de l'élément à tester, identifier l'adresse du bit a tester et tester le bit.
    Heureusement, il y a une instruction assembleur qui fait ça directement. Mais elle n'est pas aussi rapide qu'un simple lookup dans un tableau.

    Pour ce qui est du Pos, c'est beaucoup, beaucoup plus lent. Avec le tableau lookup, tu lis un caractères en entrée, tu fais une lecture directe dans le tableau et tu connais le résultat. Globalement, tu fais un test par caractère.

    Avec un Pos, tu lis un caractère en entrée, puis tu le compare au premier caractère de la chaîne de référence, puis au deuxième, au troisième... jusqu'à avoir trouver celui qui t'intéresse.
    Donc il faut que tu testes un par un tous les caractères du jeu latin avant de te rendre compte que le caractère n'est pas bon.
    Avec les autres méthodes, tu n'as toujours qu'un seul et unique test.

    Faites les tests :
    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
     
    function TestSet(const s : string) : boolean;
    var
      p : pchar;
    begin
      if s = ''
      then result := true
      else begin
        result := true;
        p := @s[1];
        while (p^<>#0) and result do
        begin
          result := result and (p^ in okChars);
          inc(p);
        end;
      end;
    end;
     
    function TestTableau(const s : string) : boolean;
    var
      p : pchar;
    begin
      if s = ''
      then result := true
      else begin
        result := true;
        p := @s[1];
        while (p^<>#0) and result do
        begin
          result := result and CharIsOk[p^];
          inc(p);
        end;
      end;
    end;
     
    function TestPos(const s : string) : boolean;
    var
      p : pchar;
    begin
      if s = ''
      then result := true
      else begin
        result := true;
        p := @s[1];
        while (p^<>#0) and result do
        begin
          result := result and (pos(p^, ChaineLatine)>0);
          inc(p);
        end;
      end;
    end;
    Avec :
    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
     
    var
      okChars : set of char = ['a'..'z', 'A'..'Z', '0'..'9'];
      CharIsOk : array[char] of boolean;
      ChaineLatine : string;
     
    var
      cpt : char;
     
    initialization
      ChaineLatine  := '';
      for cpt := low(CharIsOk) to high(CharIsOk) do
      begin
        CharIsOk[cpt] := cpt in okChars;
        if CharIsOk[cpt]
        then ChaineLatine := ChaineLatine + cpt;
      end;
    end.
    J'obtiens :
    TestSet : 357ms.
    TestTableau : 228ms.
    TestPos : 6 340ms.

  11. #11
    Membre habitué

    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    639
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 639
    Points : 167
    Points
    167
    Par défaut
    Question toute bête, à la déclaration de CharIsOk il me dit : le nombre d'élément diffère de la déclaration.

    voici mon code , j'ai pourtant bien l'impression d'avoir mes 255 éléments :
    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
    const
      CharIsOk : array[char] of boolean = (
      false, false, false, false, false, false,
      false, false, false, false, false, false,
    false, false, false, false, false, false,
    false, false, false, false, false, false,
    false, false, false, false, false, false,
    false, false, false, false, false, false,
    false, false, false, false, false, false,
    false, false, false, false, false, false,
    false, false, false, false, false, false,
    false, false, false, false, false, false,
    false, false, false, false, false, false,
    false, false, false, false, false, false,
    false, false, false, false, false, false,
    false, false, false, false, false, false,
    false, false, false, false, false, false,
    false, false, false, false, false, false,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true, true, true, true, true, true,
    true,true,true);

  12. #12
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 263
    Points
    3 263
    Par défaut
    Salut,

    Il manque un seul true à la fin. (Suffisait d'en rajouter ou d'en enlever à la fin jusqu'à ce que le compilo arrête de tousser).

    A+

    EDIT même jour 17h18 : Au fait il me semblait que tu voulais retenir seulement les caractères latins (de a à z, de A à Z, plus les caractères de ponctuation et éventuellement les caractères accentués français or avec la tartine de 'true' située à la fin de ton CharIsOk tu dois ramasser plein de caractères qui ne sont ni français ni latins, faudrait choisir avec ta table de caractères.
    N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  13. #13
    Membre habitué

    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    639
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 639
    Points : 167
    Points
    167
    Par défaut
    ok
    c'était juste pour faire un test.
    Par contre je suis surpris par la rapidité, j'ai un fichier de 1200000 lignes, et je mets un caractère non autorisé a la ligne 540000, avec des lignes de 68 caractères, et il met 3 secondes a me dire quelle ligne a ce caractère.
    je vais des tests plus poussé parce que là ça me sidère.

  14. #14
    Expert confirmé

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Leader Technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Points : 4 170
    Points
    4 170
    Par défaut
    Donc tu dois lire 540000*68 caractères pour trouver l'erreur.
    Ca représente grosso modo 40 Mo à lire séquentiellement. De nos jours, un disque dur est capable de lire trois fois plus de données en une seconde.

    3 secondes pour scanner 40 Mo, je pense qu'on doit pouvoir encore améliorer ça.
    Les secondes comprennent le temps de lecture du fichier ? Si c'est le cas, tu peux grandement améliorer les performances en travaillant avec un fichier binaire au lieu d'un fichier text et en travaillant directement sur les données binaires, sans te préoccuper du découpage en lignes.
    Pendant le scan, tu pourrais détecter les retours à ligne (caractère #13 et #10) pour compter les lignes au fur et à mesure du scan.
    De plus tu pourrais également améliorer les perfs en multi-threadant le tout :
    - Tu as un thread qui lit un bloc de donnée sur le fichier. Lorsqu'il a finit la lecture, il place le bloc dans une file d'attente et commence à lire un autre bloc de données sur le disque.
    - Pendant ce temps, un deuxième thread traite la file des blocs lus pour faire le scan.
    L'intérêt de la chose, c'est qu'un accès disque c'est essentiellement des temps d'attente et de la logique cablée.
    En multi-threadant l'appli, on peut récupérer les temps d'attentes pour effectuer le scan des données. De cette façon, la recherche peut s'effectuer à la vitesse de l'élément le plus lent : La lecture du disque, ou le scan des données. Si on ne multi-thread pas le traitement, on additionne durées des deux traitements.

    Bon j'arrête le délire, visiblement la solution actuelle est déjà suffisante pour satisfaire tes besoins.

    PS: Pour CharIsOk, j'avais déclaré une constante typée pour présenter rapidement le principe, mais tu ferais mieux de déclarer une variable et de l'initialiser avec un bout de programme. Parce que un tableau de 256 boolean, c'est pas très lisible... on a vite fait de se planter.

  15. #15
    Membre habitué

    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    639
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 639
    Points : 167
    Points
    167
    Par défaut
    Merci pour ces précisions!!
    Effectivement, les besoins des utilisateurs ne méritent pas un investissement en temps de développement trop important. Et déjà si je leur annonce un temps de 4 sec pour un fichier d'un million de lignes, ils vont m'offrir le resto a la Tour d'argent.

    Merci pour ton aide en tout cas!

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

Discussions similaires

  1. Analyseur syntaxique descendant
    Par jalam dans le forum Langages de programmation
    Réponses: 6
    Dernier message: 02/01/2007, 08h15
  2. Analyseur Syntaxique Expression Booléenne
    Par Invité dans le forum Langage
    Réponses: 8
    Dernier message: 01/10/2006, 10h57
  3. Analyseur syntaxique HTML
    Par roudoudouduo dans le forum Outils
    Réponses: 5
    Dernier message: 03/07/2006, 16h52
  4. analyseur syntaxique
    Par tomy29 dans le forum Langage
    Réponses: 11
    Dernier message: 11/01/2006, 12h45
  5. [Conception] Analyseur Syntaxique
    Par guu dans le forum Général Java
    Réponses: 7
    Dernier message: 03/01/2006, 12h28

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