Marotte ⛧ a écrit 8780 commentaires

  • # Ça avance

    Posté par  . En réponse au journal Analyse de texte. Évalué à 2.

    À la base j’aurais pas dû poster ça dans un journal mais dans un forum. Le fait que ce soit un journal m’incite à continuer à poster mon code…

    Voici donc la dernière version de Reader.py, script dont le but est de prendre n’importe quel fichier texte en entrée, le découper en « phrases » et stocker la fréquence d’apparition de ces « phrases » dans une base SQLite.

    #!/usr/bin/env python3
    
    """Reader.py: Read text for sentences frequencies."""
    __author__ = "M4rotte"
    __copyright__ = "Copyright 2015, Institut Marotte for Mouling"
    __license__ = "GPL"
    __version__ = "0.4"
    
    import sys
    import re
    import sqlite3
    from collections import Counter
    
    class Reader:
      def __init__(self):
        self.sb             = ''
        self.characters     = Counter()
        self.sentences      = Counter()
        self.signature      = ''
        self.sig96          = ''
        self.start          = re.compile(r'^(\n|)[\-–—«ÉÀÇÔÎÖÏA-Za-z]$')       # If string buffer (self.sb) match, just read next character.
        self.stop           = re.compile(r'(.|\n)+[.!?…:]( |\n)$')             # If self.sb match, consider self.sb valid sentence, store it in self.sentences and reset self.sb.
        self.discard        = re.compile(r'^(([0-9]+)([\\:]+)|##)(.*)(\n|)')   # If self.sb match, just drop it.
        self.correct_tiret  = re.compile(r'^( |)-')                            # If match (it's obviously part of a dialog), replace the tiret with the designed Unicode character.
        self.cancel_stop    = re.compile(r'(.*|)( |\n)(M|Me)(\.)( |\n|)$');    # If match (means it matched self.stop first…), just don't "stop" and read next character.
        self.nb_insert      = 0   # Number of inserts off the last read()
        self.nb_update      = 0   # Number of updates off the last read() 
        self.nb_record      = 0   # Number of records in the updated database
    
      def read(self,f):
        """Read input and populate `sentences`"""
        while True:
          c = f.read(1)
          if not c:
            break
          if c == '\xa0':
            c = ' '
          self.characters[c] += 1  
          self.sb += c
          if self.sb in [' ','\n','»']:
            self.sb = ''  
            continue
          if self.discard.match(self.sb):
            self.sb = ''
            continue
          if self.start.match(self.sb):
            continue
          if self.stop.match(self.sb) and not self.cancel_stop.match(self.sb):
            if self.correct_tiret.match(self.sb):
              self.sb = self.sb.replace('-','–') 
            self.sentences[self.sb.strip()] += 1
            self.sb = ''
            continue
        for c in self.characters.most_common():
          self.signature += c[0]
        self.sig96 = self.signature[:96].replace('\n',' ')  
    
      def store(self,dbfile='reader.sqlite'):
        """ Update the database from `sentences` """
        connection = sqlite3.connect(dbfile)
        cursor = connection.cursor()
        cursor.execute('create table if not exists sentences (sentence text primary key unique, freq int)')
        ## For futur use :) # cursor.execute('create virtual table if not exists fts_strings using fts4(string text, freq int, tokenize=unicode61 "remove_diacritics=0" "tokenchars= ")')
    
    
        # Store `sentences` into database
        for s in self.sentences.most_common():
          try:
            cursor.execute("insert into sentences values (?, ?)",(s[0], s[1]))
            self.nb_insert += 1
          except sqlite3.IntegrityError:
            self.nb_update += 1
            cursor.execute("update sentences set freq=freq+? where sentence = ?",(s[1],s[0]))
        self.nb_record = cursor.execute('select count(*) from sentences;')
        sys.stderr.write('Database update: '+str(self.nb_insert)+' inserts '+str(self.nb_update)+' updates '+str(self.nb_record.fetchone()[0])+' records. SIG96 : '+str(self.sig96)+'\n')
        connection.commit()
    
    try:
      reader = Reader()
      reader.read(sys.stdin)
      reader.store()
    
    
    except KeyboardInterrupt as error:
      print ('\n'+repr(error),file=sys.stderr)
      sys.stderr.flush()
      sys.stdout.flush()
      exit(1)

    La sortie en partant d’une base inexistante et en la renseignant à partir de classiques de la littérature française, posts du bouchot et contenu issu de Wikipédia (histoire d’avoir des entrées assez hétérogènes) :

    $ for f in *.txt; do ./Reader.py < "$f"; done; sqlite3 ../linuxfr.org.sqlite 'select message from posts;' | ./Reader.py ; sqlite3 ../Wikipedia.sqlite 'select fact from facts;' | ./Reader.py 
    Database update: 7498 inserts 0 updates 7498 records. SIG128 :  eaistnrulodcmp v,é’fqh.gbàx-jyè;–ALê?«»zkC!SEJMKDI:WPçO…îôâQVNT#œû_ùwBUïRG1FYÀ2()É307H5486][9ÔX
    Database update: 7533 inserts 74 updates 15031 records. SIG128 :  eaistnrulodcpm v,é’qf.hbgàjx-yè–;AêL?«»kCzE!SM:JIPDKWîçVôNOTâQ_…û#ùœBw0RïU1ÀF2G()3YHÉ5][847°69ü
    Database update: 7367 inserts 33 updates 22398 records. SIG128 :  easitnrulodcmp ,év’f.qgbhàèxj-êyMIL;EPCS«»Az!RâçJ:DFVûîTô…?ùOGQ–UœNïÀB1É8H{Ç45/kë#0w397XÔ2Z)6—]
    Database update: 2496 inserts 2 updates 24894 records. SIG128 :  esatinrulodcpmé, v'qfgbh.àxèCy;jê-LAG\:IRzôSBçâTHPîDûVMEù12Q3O«4»N5ï0U687œ?9FÉJ)(_!…ëÀW
    Database update: 10914 inserts 71 updates 35808 records. SIG96 :  easitnrulodc mp,év’.bfhgqxà»!èj«;-yMAêIECLFDz?P:çSRâOVJîTôQUBùN—…ûHG()ïk1#8X3Ç2w4590Yë6óW7Z\áñú
    Database update: 1359 inserts 15 updates 37167 records. SIG96 :  esitanrulodpmc '.é,v-qbfghjàxJèIEC!:ML?TyAêçPzQOS»«BVHûRîâùXôÇDNU2ï1F3()69À05Éë8Z°;7
    Database update: 10707 inserts 62 updates 47874 records. SIG96 :  eaistnrulodmpc év,’q.fhbgàjMx-èJêyL;CIz–!ERSVAP?Dâç:ûôQî…FBTNOœUùÀ#XHGÉï1*()0»«8Kw637k°924YW5ÊZ
    Database update: 5734 inserts 79 updates 53608 records. SIG96 :  eastinrulodcmp év'.,fqgbh-àjTxèyIêL!çJEC«»A?kMHPSzDOB…Nô*Qûâ:RUîV{ùXœ_ÀÇwGF;1ÉW/()2ï][YZ07438}Î
    Database update: 7114 inserts 64 updates 60722 records. SIG96 :  easintrulodm,cp vé’qf.hgbàjxè—-yêM:L!zEACJ?IP;çD»…«FôSVùTâOûNBQîR–œUHGÀ1kÉw2X907K5ü84ï#ëäÇY3WÈÊ
    Database update: 10690 inserts 123 updates 71412 records. SIG96 :  eastinrulodc,mp vé'.fghbq-àjxè!yMEêLC;N…zIPçADSâF?VBT:OôJûùîGURHQZœ_À»«Çk*{Éw1Xïë4Ô05W2Ê73Y
    Database update: 24771 inserts 29 updates 96183 records. SIG96 :  eastinruol:cpdm1 20fh/vé'5b3.qg4-,j76<>98"wyx?à[]=ç͌!kèêzCA’_;&SET)LPMOINJD(FBRU\VHG%ô…+W̚҉Qû█«
    Database update: 67825 inserts 14 updates 164008 records. SIG96 :  eainrstoludcmép,. ghvbf1q'()y9L02ACxè-MSjPàBk†8DRJ3IGçF5746T:EzNê°HV’OKUwÉ«W»Xôûî;ïZâYQœ%áù/í"ë
    

    On peut voir que l’intégration du contenu Wikipédia amène à certains biais (et c’est pas Me Soleil qui s’en plaindra…) mais que « Ah ! » et « Oh ! » restent des valeurs sûres :

    $ sqlite3 reader.sqlite "select * from sentences  order by freq desc limit 30;"
    Signe du zodiaque :|358
    M.|224
    Ah !|194
    « Ah !|181
    – Ah !|180
    Mgr Paul Guérin, Vie des saints ; t.|162
    – Oh !|148
    Pas de journée internationale répertoriée pour cette date.|134
    Oh !|100
    « Oh !|87
    Les noms de plusieurs voies, places, sites ou édifices, de pays ou régions francophones, contiennent cette date sous diverses graphies :|66
    – Eh bien !|59
    France :|59
    Eh bien !|56
    États-Unis :|52
    Décembre :|49
    Bahaïsme :|47
    Février :|46
    Juin :|43
    – Tiens !|40
    Octobre :|40
    Hein ?|39
    –C'est quoi ça ?|39
    Mai :|39
    Fêtes religieuses romaines :|39
    Mars :|38
    « Non !|37
    dit Frédéric.|36
    Japon :|36
    — Ah !|35
    

    Vous pouvez reprendre une activité normale.

  • [^] # Re: Version 0.3

    Posté par  . En réponse au journal Analyse de texte. Évalué à 2.

    En modifiant un peu le code voilà ce que ça donne sur un extrait de bouchot standard :

    self.start      = re.compile(r'^(\n|)[\-–—<«ÉÀÇÔÎÖÏA-Za-z]$')
    if self.sb == ' ' or self.sb == '\n' or self.sb == '«' or self.sb == '»' or self.sb == '<' or self.sb == '>':
      self.sb = ''
    
    sqlite> select * from sentences order by freq desc limit 40;
    ..|1704
    <a href="http:|818
    <a href="https:|361
    youtube.|359
    com/watch?|356
    imgur.|259
    [:|211
    pr0gramm.|193
    !!|158
    wikipedia.|154
    lemonde.|115
    twimg.|114
    moul.|92
    lefigaro.|66
    20minutes.|62
    )
    22:|55
    o
    20:|52
    programme.|48
    /
    20:|48
    /
    21:|46
    )
    20:|46
    yahoo.|45
    o
    21:|43
    o
    17:|42
    news.|42
    co.|42
    google.|42
    ??|41
    nouvelobs.|41
    -C'est quoi ça ?|39
    )
    16:|35
    liberation.|35
    o
    16:|35
    /
    22:|34
    /
    17:|33
    o
    22:|33
    pan !|32
    php?|32
    gouv.|32
    02 [:|31
    

    Ça donne des informations intéressantes sur les domaines des liens POSTé :)

  • [^] # Re: Version 0.3

    Posté par  . En réponse au journal Analyse de texte. Évalué à 2. Dernière modification le 22 décembre 2015 à 00:06.

    if self.sb == ' ' or self.sb == '\n' or self.sb == '«' or self.sb == '»':

    Je devrais je pense créer un re.reset pour celle là…

  • [^] # Re: Version 0.3

    Posté par  . En réponse au journal Analyse de texte. Évalué à 2.

    J’ai zappé le time :/

    real    1m30.632s
    user    1m25.840s
    sys 0m0.640s
    
  • # Version 0.3

    Posté par  . En réponse au journal Analyse de texte. Évalué à 2. Dernière modification le 21 décembre 2015 à 23:36.

    Merci encore pour toutes vos suggestions. Il faut souligner qu’elles étaient toutes plutôt pertinentes… J’ai pu appliquer beaucoup de vos conseils même si j’ai dû abandonner certains (je pense notamment au islice du module itertools, qui est exactement ce que je cherchais à faire…) parce que je suis parti sur d’autres types de variables et une nouvelle approche du problème.

    D’une point de vue fonctionnel je désire ne plus saucissoner l’input à l’arrache mais essayer de découper sur les phrases en me basant sur les règles typographiques (une phrase finit par un point, '«' ouvre un dialogue (ou pas…), etc…). Ça fait nettement moins d’enregistrements en base !

    D’un point de vue technique j’ai utilisé une classe afin que le code principal soit plus clair.

    Donc voici le code, j’ai viré les commentaires inutiles et il est de toute façon plus concis.

    #!/usr/bin/env python3
    
    """Reader.py: Read text for sentences frequencies."""
    __author__ = "M4rotte"
    __copyright__ = "Copyright 2015, Institut Marotte for Mouling"
    __license__ = "GPL"
    __version__ = "0.3"
    
    import sys
    import re
    import sqlite3
    from collections import Counter
    
    class Reader:
      def __init__(self):
        self.sb          = ''
        self.characters  = Counter()
        self.sentences   = Counter()
        self.start      = re.compile(r'^(\n|)[\-–—«ÉÀÇÔÎÖÏA-Za-z]$')
        self.stop       = re.compile(r'(.|\n)+[.!?…:]( |)$')
        self.nb_insert  = 0
        self.nb_update  = 0
        self.discard    = re.compile(r'^(([0-9]+)([\\]+)|^//).')
    
    
      def read(self,f):
        """Read input and populate `sentences`"""
        while True:
          c = f.read(1)
          if c == '\xa0':
            c = ' '
          self.sb += c
          self.sb = self.sb.replace('  ',' ')
          if not c:
            break
          if self.start.match(self.sb):
            continue
          if self.stop.match(self.sb):
            self.sentences[self.sb] += 1
            self.sb = ''
            continue
          if self.sb == ' ' or self.sb == '\n' or self.sb == '«' or self.sb == '»':
            self.sb = ''  
    
      def store(self,dbfile):
        """ Update the database from `sentences` """
        connection = sqlite3.connect(dbfile)
        cursor = connection.cursor()
        cursor.execute('create table if not exists sentences (sentence text primary key unique, freq int)')
        ## For futur use :) # cursor.execute('create virtual table if not exists fts_strings using fts4(string text, freq int, tokenize=unicode61 "remove_diacritics=0" "tokenchars= ")')
    
    
        # Store `sentences` into database
        for s in self.sentences.most_common():
          if not self.discard.match(s[0]):
            try:
              cursor.execute("insert into sentences values (?, ?)",(s[0], s[1]))
              self.nb_insert += 1
            except sqlite3.IntegrityError:
              self.nb_update += 1
              cursor.execute("update sentences set freq=freq+? where sentence = ?",(s[1],s[0]))
        sys.stderr.write('Database update: '+str(self.nb_insert)+' inserts '+str(self.nb_update)+' updates. \n')
        connection.commit()
        connection.commit()
    
    try:
      reader = Reader()
      reader.read(sys.stdin)
      reader.store('reader.sqlite')
    
    
    except KeyboardInterrupt as error:
      print ('\n'+repr(error),file=sys.stderr)
      sys.stderr.flush()
      sys.stdout.flush()
      exit(1)

    D’un point de vu performance je trouve que ça tourne pas mal (à partir d’une base inexistante) :

    $ time for f in *.txt; do ./Reader.py < "$f"; done;
    Database update: 7537 inserts 0 updates. 
    Database update: 7569 inserts 76 updates. 
    Database update: 7402 inserts 35 updates. 
    Database update: 2496 inserts 2 updates. 
    Database update: 11022 inserts 72 updates. 
    Database update: 11052 inserts 69 updates. 
    Database update: 5825 inserts 44 updates. 
    Database update: 7148 inserts 64 updates. 
    Database update: 10743 inserts 108 updates.
    

    Les fichiers sont des classiques de la littérature issus de sites comme http://www.ebooksgratuits.com/ (principalement), convertis from EPUB par un script choppé sur github. Les fichiers ayant été ensuite légèrement toilettés à la main est au grep avant traitement… Ça représente 6,6M de texte UTF-8.

    Voici le résultat de quelques requêtes effectuées sur la base suite au traitement de ces fichiers :

    sqlite> select * from sentences order by freq desc limit 10;
    M.|213
    Ah !|184
    « Ah !|181
    - Oh !|112
    - Ah !|98
    Oh !|91
    « Oh !|85
    – Ah !|67
    Eh bien !|54
    - Tiens !|38
    
    sqlite> select * from sentences where sentence like '%?' order by freq desc limit 10;
    Hein ?|33
    - Hein ?|27
    – Pourquoi ?|18
    « Eh bien ?|13
    pourquoi ?|12
    quoi ?|11
    « Pourquoi ?|11
    – Pourquoi cela ?|10
    – Comment cela ?|9
    « Comment ?|9
    
    sqlite> select * from sentences where sentence like '%moule%' order by freq desc limit 10;
    « Il n’y a plus de ténors, disait-il, le moule en est brisé.|1
    Mme Arnoux fit exhiber les moules pour les ouvrages plus difficiles.|1
    

    J’ai déjà noté que je devrais appliquer mon expression régulière "discard" dans la fonction read() plutôt qu’au niveau store()…

  • [^] # Re: Tout faire en base

    Posté par  . En réponse au journal Analyse de texte. Évalué à 2.

    Ce qu’il dit, je pense, c’est que les gains apportés par le fait de faire le plus possible de chose en SQL (et je dois dire qu’on peut vraiment faire un tas de trucs insoupçonnés dans les différentes variantes SQL…), par le moteur SQL, ça prends plus de sens pour un SGBD client/serveur… ça évite des « aller-retours »…

  • [^] # Re: En memoire

    Posté par  . En réponse au journal Analyse de texte. Évalué à 2.

    Tu n'as pas besoin des propriété ACID. Il n'y a qu'un utilisateur à la fois sur ta db, non ?

    Pour l’instant.

    Entendons nous bien, ce n’est pas pour ce caractère que j’ai pris SQLite. En plus des raisons déjà évoquées c’est que MariaDB je connais pas mal alors que SQLite je découvre un peu.

    Peut-être un redis qui travaille au maximum en mémoire avec un système clé / valeur.

    Ou encore BerkeleyDB. Mais je ne veux pas me limiter à un système clé-valeur pour les autres fonctionnalités que j’ai en tête. Je compte utiliser les tables virtuelles avec recherche de texte (FTS), par exemple.

  • [^] # Re: En memoire

    Posté par  . En réponse au journal Analyse de texte. Évalué à 2.

    Attention avec les dict ça bouffe très vite énormément de mémoire.

    Oui… quand on parcourt toutes les combinaisons possibles rien qu’entre caractères lus ça va vite très vite.

    Pour la mémoire j’ai abandonné le deque pour stocker mon tampon, le problème étant qu’un deque n’est pas adressable à l’aide de slices ([:4])… contrairement à un string. J’ai bien profité du conseil concernant collections.Counter(), c’est vraiment le type de variable dont j’avais besoin.

    J’ai un peu changé d’approche pour conserver les « strings » (sentences), je me base sur des expressions régulières, c’est plus propre. Dès que j’ai un truc correct je le postici.

    De plus tu utilise sqlite, je ne connais pas les performance de ce moteur pour les update mais peut être que choisir mysql(ou mariadb)

    Alors là attention, que ça puisse fonctionner plus ou ou moins vite sous MariaDB c’est clairement pas un angle d’étude pour le moment… J’utilise sqlite parce que c’est parfaitement adapté à la modélisation (et c’est par ailleurs l’un des meilleurs moteur opensource de base relationnelle). SQLite ça marche partout. sqlite passe le test ACID : https://fr.wikipedia.org/wiki/Propri%C3%A9t%C3%A9s_ACID je n’en suis pas si sûr pour MarioleDB…

  • [^] # Re: I like =

    Posté par  . En réponse au journal Analyse de texte. Évalué à 2.

    Je viens de tester avec = à la place de like les performances sont bien meilleures effectivement :)

    Merci à vous deux. Le temps d’exécution est passé de 15 min à 40 s (environ)…

    Pour le nombre de chaque requête je ne sais pas encore, je garde en tête ta remarque très judicieuse sur l’ordre d’exécution.

  • [^] # Re: Je ne ferais pas ça comme ça.

    Posté par  . En réponse au journal Analyse de texte. Évalué à 2.

    En incluant les suites telles que "a ma" je peux toujours par la suite filtrer avec une expression régulière pour n’avoir que les mots.

  • [^] # Re: occurrence des mots

    Posté par  . En réponse au journal Analyse de texte. Évalué à 3.

    C’est volontaire de vouloir prendre les signes de ponctuation…

    Pour moi 'mice' et 'mice.' ne sont pas deux chaînes identiques. De la deuxième on peut présager que le mot « mice » a des chances de terminer une phrase. À part le remplacement des retour à la ligne par des espaces puis la réduction des espaces consécutives à une seule espace je travaille en mode suite de caractères.

  • [^] # Re: Je ne ferais pas ça comme ça.

    Posté par  . En réponse au journal Analyse de texte. Évalué à 3.

    en fait tu sembles vouloir compter n'importe quel groupe de lettres…

    Oui c’est ça. N’importe quel groupe de caractères en fait.

    C'est quoi le but?

    Y’en a pas vraiment… je fais des essais on va dire…

  • [^] # Re: On dirait du C

    Posté par  . En réponse au journal Analyse de texte. Évalué à 2.

    Merci pour tous ces conseils avisés ! Surtout pour le collections.Counter je pense que ça va me servir…

    import fileinput
    for line in fileinput.input():

    Ma ligne peut avoir une longueur variable. J’aurais toujours besoin de la traiter en morceau de N caractères car je ne vais pas itérer sur tous les caractères de la ligne si je n’ai pas besoin de conserver des chaînes de plus de N caractères. J’ai également besoin d’avoir la fréquence de chaînes telles que "titi\ntoto" je devrais donc conserver un certain nombre de caractères de la ligne précédente à chaque fois…

    J’ai trouvé plus simple d’avoir une sorte de « fenêtre » (buf) qui va « glisser » sur mon entrée… Par exemple si je prends un MAXLEN de 2 et que mon entrée est "abcd\n" j’aurais tour à tour :

    • ab
    • bc
    • cd
    • d\n

    Avec MAXLEN à 3 j’aurais, en plus :

    • abc
    • bcd
    • cd\n

    si tu crois que tu as besoin de gérer la mémoire toi-même en Python

    Non, j’ai bien conscience que ce n’est pas à moi de gérer la mémoire.

  • [^] # Re: Je ne ferais pas ça comme ça.

    Posté par  . En réponse au journal Analyse de texte. Évalué à 3.

    As-tu au moins essayé de mettre une trace entre l’analyse du texte et la mise à jour de la base de données pour en être sûr ?

    Je le vois simplement grâce au sys.stderr.write(…) qui est fait entre chaque étape, la première étape (chargement) et la deuxième (suppression des chaînes qui coupent des mots en deux, sauf les petites…) s’exécutent en un temps acceptable.

    Personnellement, je lirais l’entrée par ligne, je splitterais sur les espaces et signes de ponctuation (ou tout ce qui n’est pas une lettre), comme ça, j’aurais directement les mots et ensuite seulement, pour chaque mot, j’itérerais sur la lettre de départ et la longueur pour avoir les groupes de lettres.

    En faisant ça si j’ai une première ligne qui contient "voici une première ligne" et une seconde qui contient "et là une deuxième" je n’aurais pas d’entrée créée contenant le dernier mot de la première et le premier de la deuxième ("ligne et"). Je n’aurais pas non plus 'e e', 'e et', etc… (je remplace systématiquement "\n" par "n"…)

    J’utilise donc un tampon de MAXLEN caractères qui se décale de MAXLEN-1 caractères à chaque fois afin que le dernier caractère du précédent tampon se retrouve premier du tampon suivant. Pour ça un deque me semblait plus adapté qu’un string

    je chargerais tout le texte en mémoire (mon premier ordinateur avait 8 Ko de mémoire

    Comme tu peux le voir le programme lit l’entrée standard, pour l’instant il attend EOF pour traiter les données mais à terme je veux qu’il puisse tourner en continue, en faisant un màj de la base tous les N tampons/caractères.

  • [^] # Re: nltk

    Posté par  . En réponse au journal Analyse de texte. Évalué à 3.

    si considérer le texte comme un sac de mots te suffit

    Comme un sac de caractères même… :)

    Je me pencherai sur NLTK un de ces jours ça a l’air bien mais là je veux une approche plus « bête », basée seulement sur les fréquences d’apparition.

  • [^] # Re: nltk

    Posté par  . En réponse au journal Analyse de texte. Évalué à 2.

    Très intéressant, merci.

  • [^] # Re: En memoire

    Posté par  . En réponse au journal Analyse de texte. Évalué à 2.

    [edit: vas y efface, c'est ce que tu fais deja j'ai mal lu ton code]

    Euh… bah non :)

    Utiliser time() je sais faire mais je ne l’ai pas fait ici, je lance simplement le script précédé de la commande time. Vu la sortie d’erreur je sais à peu près combien de temps prend chaque étape. Je remarque nettement que ça va à une vitesse correct quand la base est vide (donc que les INSERT aboutissent).

    A priori, ta structure de donnee comptant les syllabes/mots ne devraient pas augmenter lineairement avec la taille de tes textes

    Oui. Plus les textes passeront plus il aura de mises à jour et moins d’insertions.

    Pourquoi ne pas stocker l'information en memoire (et ne la mettre dans la base de donnee qu'a la fin)

    C’est ce que je vais faire.

  • [^] # Re: on teste le seuil bas de moinsage ?

    Posté par  . En réponse au journal La fin de la fin.. Évalué à 2.

    En te moinssant je participe à 33% de ta note à moi tout seul, ça me console.

  • [^] # Re: DMP et SESAM-Vitale: des certifications aussi

    Posté par  . En réponse au journal la fin des logiciels libres de comptabilité et de gestion de caisses. Évalué à 2. Dernière modification le 15 décembre 2015 à 02:01.

    Je demande parsque les kits de developement four-tout avec de multiples versions des protocoles rendent parfois les dévelopements triviaux

    Je viens de tomber sur ton commentaire. Est-ce que par « trivial » tu ne voulais pas tout à fait signifier l’inverse ?

    Parce que la définition de « trivial » c’est :

    Qui est banal, commun, qui relève du simple bon sens, de la réalité la plus évidente

    alors que « kits de developement four-tout avec de multiples versions des protocoles »

    ça pue un peu la complexité…

    http://www.larousse.fr/dictionnaires/francais/trivial

    :)

  • # Erratum

    Posté par  . En réponse au journal Analyse de texte. Évalué à 2.

    Le premier commentaire est erroné :

    s/~which don't match~/which match/

  • [^] # Re: false

    Posté par  . En réponse au journal Le core utile. Évalué à 4.

    Le genre de code qui va (si je n’y suis pas habitué pour une raison ou une autre) me nécessiter une heure pour rechercher sur le web et assimiler (c’est à dire accepter en son âme de codeur, profondément, que cela puisse pertinemment s’écrire ainsi…) avant de passer à la suite du code…

    J’ai dit « concis && élégant », j’aurais du ajouter lisible pour le commun des programmeurs :)

    Il faut reconnaître que l’« expansion de variable » en shell c’est une des caractéristiques de ce genre de langage et c’est rudement pratique.

  • [^] # Re: false

    Posté par  . En réponse au journal Le core utile. Évalué à 2.

    $ if (rm test); then echo ok; fi
    rm: cannot remove `test': No such file or directory
    $ touch test; if (rm test); then echo ok; fi
    ok
    

    Bah c’est justement ce que je dis, dans le premier cas la commande a un code retour ≠ 0 la condition est fausse alors que dans la deuxième le code retour est 0 est la condition est vrai :

    ≠ 0 implique faux
    0 implique vrai

    Donc c'est plus logique d'attribuer 0 à ok et !0 à toutes les situations non ok.

    Oui mais quand on apprend la logique on note 0 = faux et 1 = vrai, c’est le contraire en shell.

    Dans les autres langages de programmation on également plutôt l’habitude qu’une valeur différente de zéro soit évaluée vraie et zéro soit évalué faux.

  • [^] # Re: Des oublis ?

    Posté par  . En réponse au journal Le core utile. Évalué à 2.

    est-ce une bonne idée de s'en servir

    Ça t’évite de finir par devoir retaper deux fois des commandes quand tu te retrouves sur un AIX qui ne connaît que more, parce que tes doigts tapent less plus vite que ton cerveau ne réfléchit ^^

    D’après le man de more:

    Cette version est particulièrement primitive. Les utilisateurs doivent se convaincre que
    less(1) constitue une excellente émulation de more(1) avec en plus de nombreuses améliorations.

    Le fait que ce programme soit toujours disponible ne serait-il pas lié à la norme POSIX ?

  • [^] # Re: false

    Posté par  . En réponse au journal Le core utile. Évalué à 5.

    Entre le programme true, et le programme [ , je trouve que le shell c'est de la bidouille …

    C’est horrible ce [… genre if [ -z $v ]; then… ça ressemble à quoi ? :) On peut même ôter le crochet fermant qui n’est autorisé par le langage que pour la seule bonne raison qu’un crochet ouvert qui reste ouvert c’est très grave… presque autant qu’une parenthèse !

    Maintenant j’essaie d’écrire : if test -z $v; then… c’est bien ce qu’il y a de plus logique et clair à lire selon moi.

    Oui le shell c’est spécial comme « langage de programmation » vu que ce n’en ai pas vraiment un.

    En m’y mettant j’ai eu un peu de mal avec la logique binaire… On a l’habitude de considérer que 1 représente vrai et 0 représente faux, or le code retour des programmes c’est 0 pour OK, par convention. Si je fais un if (rm toto) et que la commande « plante » (parce que le fichier toto n’existe pas par exemple) ma condition sera fausse.

    L’utilisation des opérateurs && et || entre plusieurs commandes permet souvent d’être concis et élégant, je trouve.

  • # Mais que fait la police ?

    Posté par  . En réponse au journal Tentative d'escroquerie téléphonique. Évalué à 0.

    Elle protège et elle sert !

    C’était sûrement l’auto-dialer (de Marge)… Ne t’inquiète pas c’est réglé.

    https://www.youtube.com/watch?v=nbbIXMDGb_w