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

Python Discussion :

remplacer un texte par un autre


Sujet :

Python

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    293
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 293
    Par défaut remplacer un texte par un autre
    Bonsoir,

    Voici un code dont le but est de remplacer un texte dans un fichier odt en utilisant la librairie pyodf :
    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
    def saxiter(node : Element) -> Iterator[Element]:
        """Return an interator over all elements reachable from node: later siblings and recursively all children."""
        while node:
            yield node
            if node.hasChildNodes():
                yield from saxiter(node.firstChild)
            node = node.nextSibling
     
    def edittextElements(doc : OpenDocument, pattern : list[str]) -> Generator[tuple[str, str], str, None]:
        """Goes over all elements, and look for the text that contains the given."""
        for elem in saxiter(doc.topnode):
            if elem.__class__ is Text:
                for pat in pattern:
                    if pat in str(elem):
                        elem.data = yield (pat, elem.data)
    J'ai trouvé ce code sur cette page : https://github.com/eea/odfpy/wiki/Re...eTextToAnother.

    Avez-vous eu l'occasion de le tester ? Personnellement je ne le comprends et je ne vois pas comment le compléter pour le rendre opérationnel.

  2. #2
    Expert confirmé
    Avatar de jurassic pork
    Homme Profil pro
    Bidouilleur
    Inscrit en
    Décembre 2008
    Messages
    4 192
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Bidouilleur
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2008
    Messages : 4 192
    Par défaut
    Hello,
    as-tu LibreOffice ou OpenOffice installé sur ton ordinateur ?
    Quel est ton O.S ?
    Ami calmant, J.P

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    293
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 293
    Par défaut
    Bonjour Jurassic,

    Oui, j'ai Libre Office et je suis sur Windows 11.

  4. #4
    Expert confirmé
    Avatar de jurassic pork
    Homme Profil pro
    Bidouilleur
    Inscrit en
    Décembre 2008
    Messages
    4 192
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Bidouilleur
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2008
    Messages : 4 192
    Par défaut
    Et pourquoi fais-tu cela avec un python externe alors que dans LibreOffice , il y a un python et on peut exécuter du code python dans des macros qui manipule les documents LibreOffice?

  5. #5
    Membre éclairé
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    293
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 293
    Par défaut
    Le but est de manipuler des fichiers odt directement depuis mes propres scripts Python et sans passer par libre Office.

  6. #6
    Expert confirmé
    Avatar de jurassic pork
    Homme Profil pro
    Bidouilleur
    Inscrit en
    Décembre 2008
    Messages
    4 192
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Bidouilleur
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2008
    Messages : 4 192
    Par défaut
    J'ai trouvé un code qui utilise pyodf qui semble pas trop mal:
    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
    from odf.opendocument import load
    from odf import text, teletype
     
    textdoc = load("D:/dev/LibreOffice/Questions2.odt")
    texts = textdoc.getElementsByType(text.P)
    s = len(texts)
    for i in range(s):
        old_text = teletype.extractText(texts[i])
        new_text = old_text.replace('Produits', 'Produit')
        new_S = text.P()
        new_S.setAttribute("stylename", texts[i].getAttribute("stylename"))
        new_S.addText(new_text)
        texts[i].parentNode.insertBefore(new_S, texts[i])
        texts[i].parentNode.removeChild(texts[i])
    textdoc.save('D:/temp/ficResultat.odt')
    Le souci c'est qu'avec le fichier Odt que j'ai en test, texts est en début de boucle composé de 28 éléments mais au fur et à mesure qu'avance la boucle le nombre d'éléments dans texts diminue si bien qu'au bout d'un moment on a une erreur list index out of range.

  7. #7
    Membre éclairé
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    293
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 293
    Par défaut
    Tout d'abord merci pour ta recherche.

    Ce code est fortement inspiré de la page citée précédemment mais fonctionne mal pour l'explication suivante : This does not work correctly, as not all texts are in Span elements. Some texts actually happen to be stuck directly, say into text.P elements. This can probably happen with other elements too, e.g. tables. All text is actually stored in odf.element.Text instances, which oops, are not odf.element.Element derived, hence, cannot be looked up with doc.getElementsByType.
    https://github.com/eea/odfpy/wiki/Re...eTextToAnother

    C'est pour cette raison que je teste la piste donnée plus bas mais pour l'instant je ne maitrise pas tout.

    Parmi l'autre piste que j'ai en tête c'est xml.etree.ElementTree. A voir...

  8. #8
    Expert confirmé
    Avatar de jurassic pork
    Homme Profil pro
    Bidouilleur
    Inscrit en
    Décembre 2008
    Messages
    4 192
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Bidouilleur
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2008
    Messages : 4 192
    Par défaut
    J'ai résolu mon problème avec ce code :
    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
    from odf import text, teletype
     
    textdoc = load("D:/dev/LibreOffice/Questions2.odt")
    texts = textdoc.getElementsByType(text.P)
    s = len(texts)
    for i in range(len(texts)):
        try:
            old_text = teletype.extractText(texts[i])
            new_text = old_text.replace('Produits', 'Produit')
            new_S = text.P()
            new_S.setAttribute("stylename", texts[i].getAttribute("stylename"))
            new_S.addText(new_text)
            texts[i].parentNode.insertBefore(new_S, texts[i])
            texts[i].parentNode.removeChild(texts[i])
        except:
            print(i)
            textdoc.save('D:/temp/ficResultat.odt')
    Ce code fonctionne pour un document qui ne contient que des paragraphes.

  9. #9
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 049
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 049
    Par défaut
    Hello,

    Une proposition,

    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
     
    doc = load('test.odt')
     
    patterns = ["Replace this"]
    gen = edittextElements(doc, patterns)
     
    try:
        while True:
            pat, old_text = next(gen)
            new_text = old_text.replace(pat, "to this")
            gen.send(new_text)
    except StopIteration:
        pass
     
    doc.save('result.odt')

  10. #10
    Expert confirmé
    Avatar de jurassic pork
    Homme Profil pro
    Bidouilleur
    Inscrit en
    Décembre 2008
    Messages
    4 192
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Bidouilleur
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2008
    Messages : 4 192
    Par défaut
    comme on est sous windows une proposition en utilisant pywin32 et l'accès aux objets COM avec win32com
    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
    import win32com.client
    import subprocess
    def PropertyValueArray(manager,num):
        '''Creates an openoffice property value array'''
        l = []
        for x in range(num):
            _p = manager.Bridge_GetStruct("com.sun.star.beans.PropertyValue")
            _p.Name = ''
            _p.Value = ''
            l.append(_p)
        return l
     
    # Start LibreOffice in server mode
    starter = ['C:/Program Files/LibreOffice/program/soffice.exe', '--accept=socket,host=localhost,port=2002;urp;', '--norestore', '--nologo', '--nodefault', '--headless']
    proc = subprocess.Popen(starter)
    # Connect to the running LibreOffice instance
    objServiceManager = win32com.client.Dispatch("com.sun.star.ServiceManager")
    objDesktop = objServiceManager.CreateInstance("com.sun.star.frame.Desktop")
    objServiceManager._FlagAsMethod("Bridge_GetStruct")
    objServiceManager._FlagAsMethod("Bridge_GetValueObject")
    p = PropertyValueArray(objServiceManager,1)
    p[0].Name = 'Hidden'  # doc should run hidden
    p[0].Value = True  # doc should run hidden
    document = objDesktop.loadComponentFromURL('file:///D:/dev/LibreOffice/Questions2.odt', "_blank", 0, p)
    search = document.createSearchDescriptor()
    search.SearchString = "Produits"
    search.SearchAll = True
    search.SearchWords = True
    search.SearchCaseSensitive = False
    selsFound = document.findAll(search)
    if selsFound.getCount() == 0:
        proc.kill()
        exit
    print(str(selsFound.getCount()) + " mots trouvés!")
    for selIndex in range(0, selsFound.getCount()):
        selFound = selsFound.getByIndex(selIndex)
        selFound.setString("MesProduits")
    # Save the document as ODT
    document.storeAsURL("file:///D:/temp/document.odt", ())
    # Close the document
    document.close(True)
    # Kill server
    proc.kill()
    1 - On lance LibreOffice en mode serveur headless
    2 - On se connecte au service
    3 - On ouvre le document source en mode Hidden
    4 - On remplace un mot par un autre mot (on peut changer les options de recherche)
    5 - On affiche le nombre de mots trouvés
    6 - On enregistre les modifications dans un autre fichier odt
    7 - On arrête le serveur LibreOffice

  11. #11
    Membre éclairé
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    293
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 293
    Par défaut
    Merci Fred pour cette suggestion. par contre lorsque je teste :
    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
    from odf import opendocument, text, teletype
    from odf.text import P
    from odf.style import Style, TextProperties, ParagraphProperties
    doc = opendocument.load(r"C:\Users\chris\Documents\mesScryptPython\fichiers odt\mon second document.odt")
     
     
    def saxiter(Element1): #-> Iterator[Element]:
        """Return an interator over all elements reachable from node: later siblings and recursively all children."""
        while node:
            yield node
            if node.hasChildNodes():
                yield from saxiter(node.firstChild)
            node = node.nextSibling
     
    def edittextElements(doc, pattern): #-> Generator[tuple[str, str], str, None]:
        """Goes over all elements, and look for the text that contains the given."""
        for elem in saxiter(doc.topnode):
            if elem.__class__ is Text:
                for pat in pattern:
                    if pat in str(elem):
                        elem.data = yield (pat, elem.data)
     
    patterns = ["code"]
    gen = edittextElements(doc, patterns)
     
     
    try:
        while True:
            pat, old_text = next(gen)
            new_text = old_text.replace(pat, "to this")
            gen.send(new_text)
            print(gen.send(new_text))
    except StopIteration:
        pass
     
    try:
        while True:
            pat, old_text = next(gen)
            new_text = old_text.replace('code', "to this")
            gen.send(new_text)
            doc.save(r"C:\Users\chris\Documents\mesScryptPython\fichiers odt\mon second document3.odt")
    except StopIteration:
        pass
    j'obtiens le message d'erreur suivant :
    Traceback (most recent call last):
    File "C:\Users\chris\Documents\mesScryptPython\fichiers odt\remplacer_texte4.py", line 39, in <module>
    pat, old_text = next(gen)
    ^^^^^^^^^
    File "C:\Users\chris\Documents\mesScryptPython\fichiers odt\remplacer_texte4.py", line 20, in edittextElements
    for elem in saxiter(doc.topnode):
    ^^^^^^^^^^^^^^^^^^^^
    File "C:\Users\chris\Documents\mesScryptPython\fichiers odt\remplacer_texte4.py", line 12, in saxiter
    while node:
    ^^^^
    UnboundLocalError: cannot access local variable 'node' where it is not associated with a value

  12. #12
    Membre Expert
    Profil pro
    Inscrit en
    Septembre 2010
    Messages
    1 512
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Septembre 2010
    Messages : 1 512
    Par défaut
    tu as mal recopié le code d'origine (source https://github.com/eea/odfpy/wiki/Re...eTextToAnother)
    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
    def saxiter(node : Element) -> Iterator[Element]:
        """Return an interator over all elements reachable from node: later siblings and recursively all children."""
        while node:
            yield node
            if node.hasChildNodes():
                yield from saxiter(node.firstChild)
            node = node.nextSibling
     
    def edittextElements(doc : OpenDocument, pattern : list[str]) -> Generator[tuple[str, str], str, None]:
        """Goes over all elements, and look for the text that contains the given."""
        for elem in saxiter(doc.topnode):
            if elem.__class__ is Text:
                for pat in pattern:
                    if pat in str(elem):
                        elem.data = yield (pat, elem.data)
    Ton paramètre element de la fonction saxiter devrait s'appeler node ou renommer les node en Element1 (nom de ton paramètre)

  13. #13
    Membre éclairé
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    293
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 293
    Par défaut
    Oups...je rectifie et... ça fonctionne.
    Un grand merci pour l'aide que vous m'avez apportée. Ce petit bout de code m'a bien fait avancé.

    Peut-être encore une question :
    Je vois dans ce code que c'est la ligne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    elem.data = yield (pat, elem.data)
    qui permet de donner directement le texte à l'élément alors que je partais sur une mauvaise piste du genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    element.parentNode.insertBefore(new_element, element)
    .
    Oui, lorsque je fais dir(elem) je retrouVe bien data dans les arguments mais de quelle manière peut-on avoir plus d'info ? help(elem) ou help(elem.data) ne donne rien.

Discussions similaires

  1. Remplacer un texte par un autre texte en fonction d'un numéro
    Par camo2b dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 19/11/2020, 09h58
  2. [WD-MAC 2011] Remplacer un texte par un autre dans plusieurs documents
    Par didcac dans le forum Word
    Réponses: 6
    Dernier message: 20/10/2011, 09h41
  3. [PDF] Remplacer un texte par un autre dans un PDF
    Par scourjean dans le forum Bibliothèques et frameworks
    Réponses: 0
    Dernier message: 24/08/2011, 09h07
  4. Remplacer un texte par un autre dans un fichier
    Par Fredo67 dans le forum Shell et commandes GNU
    Réponses: 9
    Dernier message: 08/04/2009, 16h04
  5. Remplacer un texte par un autre
    Par Guillaume602 dans le forum C++
    Réponses: 3
    Dernier message: 24/11/2005, 00h40

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