Exercice utilitaire python #50

Open
opened 2023-05-04 11:48:05 +02:00 by ciri · 36 comments
Owner
  • Créer un fichier de deux lignes ou plus dans un éditeur de texte.
  • Créer un petit utilitaire capable de lire le fichier et d'afficher son contenu.
  • Être capable de modifier l'affichage à l'écran.
- [x] Créer un fichier de deux lignes ou plus dans un éditeur de texte. - [x] Créer un petit utilitaire capable de lire le fichier et d'afficher son contenu. - [x] Être capable de modifier l'affichage à l'écran.
ciri added the
tâche
label 2023-05-04 11:48:05 +02:00
Anand was assigned by ciri 2023-05-04 11:48:06 +02:00
BoisjibaultAline was assigned by ciri 2023-05-04 11:48:08 +02:00
brandelune was assigned by ciri 2023-05-04 11:48:10 +02:00
Leodelaune was assigned by ciri 2023-05-04 11:48:11 +02:00
ciri self-assigned this 2023-05-04 11:48:11 +02:00
ciri added this to the Python project 2023-05-04 11:48:20 +02:00
ciri added the due date 2023-05-08 2023-05-04 11:48:37 +02:00
Author
Owner

J’ai utilisé deux méthodes pour afficher le fichier créé :

  1. D'abord, j'ai utilisé cette méthode, car le message d'erreur suivant s'affichait : FileNotFoundError: [Errno 2] No such file or directory: ‘Text_Python.txt’. La solution trouvée consistait simplement à indiquer le chemin d'accès du fichier :
>>> with open('/Users/sirinebenhadjkhalifa/Desktop/Utilitaire_Python/Text_Python.txt') as f:
...     file = f.read()
...     print(file)
  1. Ensuite, celle-ci avec le mode r pour lire le texte :
>>> f = open("Text_Python.txt", "r")
>>> print(f.read())
... 
I soon learned more about this flower. On the little prince's planet there had always been very simple flowers with a single row of petals which took up very little space and were no bother. They would appear one morning in the grass, and then fade the same evening.
  1. Je l’ai enfin modifié avec le mode a pour ajouter une phrase à la fin du texte :
>>> f = open("Text_Python.txt", "a")
>>> f.write("This is an extract from ‟The Little Prince”.")
45
>>> f.close()

Résultat :

>>> f = open("Text_Python.txt", "r")
>>> print(f.read())
I soon learned more about this flower. On the little prince's planet there had always been very simple flowers with a single row of petals which took up very little space and were no bother. They would appear one morning in the grass and then fade the same evening. This is an extract from ‟The Little Prince”.
>>>
J’ai utilisé deux méthodes pour afficher le fichier créé : 1. D'abord, j'ai utilisé cette méthode, car le message d'erreur suivant s'affichait : `FileNotFoundError: [Errno 2] No such file or directory: ‘Text_Python.txt’`. La solution trouvée consistait simplement à indiquer le chemin d'accès du fichier : ```python >>> with open('/Users/sirinebenhadjkhalifa/Desktop/Utilitaire_Python/Text_Python.txt') as f: ... file = f.read() ... print(file) ``` 2. Ensuite, celle-ci avec le mode `r` pour lire le texte : ```python >>> f = open("Text_Python.txt", "r") >>> print(f.read()) ... I soon learned more about this flower. On the little prince's planet there had always been very simple flowers with a single row of petals which took up very little space and were no bother. They would appear one morning in the grass, and then fade the same evening. ``` 3. Je l’ai enfin modifié avec le mode `a` pour ajouter une phrase à la fin du texte : ```python >>> f = open("Text_Python.txt", "a") >>> f.write("This is an extract from ‟The Little Prince”.") 45 >>> f.close() ``` Résultat : ```python >>> f = open("Text_Python.txt", "r") >>> print(f.read()) I soon learned more about this flower. On the little prince's planet there had always been very simple flowers with a single row of petals which took up very little space and were no bother. They would appear one morning in the grass and then fade the same evening. This is an extract from ‟The Little Prince”. >>> ```
Collaborator
  1. Fonction open

La fonction open est décrite ici :
https://docs.python.org/fr/3.11/library/functions.html?highlight=open#open

file est un objet simili-chemin donnant le chemin (absolu ou relatif au répertoire courant)

Dans notre cas, soit on sait ce qu’est le répertoire courant, soit on met un chemin absolu, comme vous l’avez fait.

Pour trouver le répertoire courant dans IDLE (ou à la ligne de commande) j’ai trouvé ceci :
https://stackoverflow.com/questions/15821121/whats-the-working-directory-when-using-idle

Si on connaît le répertoire courant, on peut utiliser un chemin relatif à celui-ci.

Remarquez que les deux syntaxes que vous employez sont très similaires. Dans les deux cas, vous assignez la ‘valeur’ de open("Text_Python.txt", "r") à une chose que vous appelez f, mais que vous pourriez appeler tout autre chose.

Le mode a veut dire append et donc les choses ajoutées au fichier avec write s’y ajouteront à la fin du fichier.

  1. Méthode read

La méthode read est décrite ici :
https://docs.python.org/fr/3/tutorial/inputoutput.html#methods-of-file-objects

Ici, read lit le contenu de f, dans le premier cas l’assigne à file, dans le second cas le passe directement à print.

  1. Fonction print

La fonction print est décrite ici :
https://docs.python.org/fr/3.11/library/functions.html?highlight=print#print

Dans le premier cas, vous appliquez print à file, qui contient f.read(), et dans l’autre vous appliquez directement print à f.read. Le résultat est donc exactement le même, mais c’est intéressant de voir qu’on peut travailler de manières différentes selon nos besoins. Peut-être qu’on aura besoin de travailler séparément sur file plus loin, alors garder f.read() dans file ça peut être utile.

  1. Méthode write

La méthode est décrite sous read.

Elle nécessite que open ait été lancé avec un mode qui autorise l’écriture.

  1. Ce qu’on peut faire maintenant

Nos fichiers vont être composés de lignes et il nous sera important de lire les fichiers ligne par ligne.

La suite de cet exercice pourrait donc être la suivante :

  • on crée un fichier qui a une dizaine de lignes
  • on ajoute une série de caractères entre chaque ligne
  • on met tout le code dans un fichier texte avec un suffixe .py
  • on lance le fichier à partir d’IDLE ou de la ligne de commande
1. ## Fonction `open` La fonction `open` est décrite ici : https://docs.python.org/fr/3.11/library/functions.html?highlight=open#open *file est un objet simili-chemin donnant le chemin (absolu ou relatif au répertoire courant)* Dans notre cas, soit on sait ce qu’est le répertoire courant, soit on met un chemin absolu, comme vous l’avez fait. Pour trouver le répertoire courant dans IDLE (ou à la ligne de commande) j’ai trouvé ceci : https://stackoverflow.com/questions/15821121/whats-the-working-directory-when-using-idle Si on connaît le répertoire courant, on peut utiliser un chemin relatif à celui-ci. Remarquez que les deux syntaxes que vous employez sont très similaires. Dans les deux cas, vous assignez la ‘valeur’ de `open("Text_Python.txt", "r")` à une chose que vous appelez `f`, mais que vous pourriez appeler tout autre chose. Le mode `a` veut dire `append` et donc les choses ajoutées au fichier avec `write` s’y ajouteront à la fin du fichier. 2. ## Méthode `read` La méthode `read` est décrite ici : https://docs.python.org/fr/3/tutorial/inputoutput.html#methods-of-file-objects Ici, `read` lit le contenu de `f`, dans le premier cas l’assigne à `file`, dans le second cas le passe directement à `print`. 3. ## Fonction `print` La fonction `print` est décrite ici : https://docs.python.org/fr/3.11/library/functions.html?highlight=print#print Dans le premier cas, vous appliquez `print` à `file`, qui contient `f.read()`, et dans l’autre vous appliquez directement `print` à `f.read`. Le résultat est donc exactement le même, mais c’est intéressant de voir qu’on peut travailler de manières différentes selon nos besoins. Peut-être qu’on aura besoin de travailler séparément sur `file` plus loin, alors garder `f.read()` dans `file` ça peut être utile. 4. ## Méthode `write` La méthode est décrite sous `read`. Elle nécessite que `open` ait été lancé avec un mode qui autorise l’écriture. 5. ## Ce qu’on peut faire maintenant Nos fichiers vont être composés de lignes et il nous sera important de lire les fichiers ligne par ligne. La suite de cet exercice pourrait donc être la suivante : - on crée un fichier qui a une dizaine de lignes - on ajoute une série de caractères entre chaque ligne - on met tout le code dans un fichier texte avec un suffixe `.py` - on lance le fichier à partir d’IDLE ou de la ligne de commande
Collaborator

Ce code ne fonctionne pas parce que je suis mauvais en Python, à vous de voir comment le corriger.

with open('test.org') as file_object:
    contents = file_object.read()
    for line in file_object: 
        line = "<seg>" + line + "</seg>"
        print(line, end='')

Ce code ne fonctionne pas parce que je suis mauvais en Python, à vous de voir comment le corriger. ```python with open('test.org') as file_object: contents = file_object.read() for line in file_object: line = "<seg>" + line + "</seg>" print(line, end='') ```
Collaborator

Travailler avec des fichiers en Python

1. Ouvrir et fermer des fichiers

Pour travailler avec des fichiers en Python, il est préférable d'utiliser la construction with open('fichier.ext') as machin: plutôt que de les ouvrir directement et les fermer manuellement.

2. Chemins des fichiers

Je vous conseille fortement d'utiliser le module pathlib pour travailler avec les fichiers.
La documentation officielle :
https://docs.python.org/fr/3/library/pathlib.html (en français)
https://docs.python.org/3/library/pathlib.html (en anglais)

Deux articles que j'ai trouvés fort utiles pour apprendre ce module :
https://pbpython.com/pathlib-intro.html
https://realpython.com/python-pathlib/

Ça peut paraître plus compliqué au début, mais l'utilisation de ce module permet d'éviter bien des maux de tête plus tard si on veut que le script fonctionne sous Linux, MacOS et Windows.

3. Mauvais en Python ?

Sans donner la réponse, je vous offre un petit indice pour comprendre pourquoi le code de Jean-Christophe ne fonctionne pas. Il faut regarder attentivement comment la fonction read() lit les fichiers et réfléchir à ce que ça implique par rapport à l'observation suivante :

Nos fichiers vont être composés de lignes et il nous sera important de lire les fichiers ligne par ligne.

Il y a au moins trois façons de modifier le code de Jean-Christophe pour qu'il donne le résultat attendu.

Je pourrai vous expliquer laquelle je choisirais et pourquoi après que vous aurez présenté les vôtres.

# Travailler avec des fichiers en Python ## 1. Ouvrir et fermer des fichiers Pour travailler avec des fichiers en Python, il est préférable d'utiliser la construction `with open('fichier.ext') as machin:` plutôt que de les ouvrir directement et les fermer manuellement. ## 2. Chemins des fichiers Je vous conseille fortement d'utiliser le module `pathlib` pour travailler avec les fichiers. La documentation officielle : https://docs.python.org/fr/3/library/pathlib.html (en français) https://docs.python.org/3/library/pathlib.html (en anglais) Deux articles que j'ai trouvés fort utiles pour apprendre ce module : https://pbpython.com/pathlib-intro.html https://realpython.com/python-pathlib/ Ça peut paraître plus compliqué au début, mais l'utilisation de ce module permet d'éviter bien des maux de tête plus tard si on veut que le script fonctionne sous Linux, MacOS et Windows. ## 3. Mauvais en Python ? Sans donner la réponse, je vous offre un petit indice pour comprendre pourquoi le code de Jean-Christophe ne fonctionne pas. Il faut regarder attentivement comment la fonction `read()` lit les fichiers et réfléchir à ce que ça implique par rapport à l'observation suivante : > Nos fichiers vont être composés de lignes et il nous sera important de lire les fichiers ligne par ligne. Il y a au moins trois façons de modifier le code de Jean-Christophe pour qu'il donne le résultat attendu. Je pourrai vous expliquer laquelle je choisirais et pourquoi après que vous aurez présenté les vôtres.
Author
Owner

Ce code ne fonctionne pas parce que je suis mauvais en Python, à vous de voir comment le corriger.

with open('test.org') as file_object:
    contents = file_object.read()
    for line in file_object: 
        line = "<seg>" + line + "</seg>"
        print(line, end='')

@Anand a réussi avec la méthode ci-dessus, mais cela n'a pas fonctionné pour @Leodelaune et moi. Voici donc les deux méthodes que nous avons utilisées et les résultats obtenus.

>>> f = open(r'/Users/sirinebenhadjkhalifa/Desktop/Utilitaire_Python/Text_Python.txt')
>>> contents = f.readline()
>>> for line in f:
...     line = "<seg>" + line + "</seg>"
...     print(line, end='')
...
<seg>very simple flowers with a single row of petals which took up very little space and were
</seg><seg>no bother. They would appear one morning in the grass, and then fade the same evening.</seg>>>>

et

>>> with open(r'/Users/sirinebenhadjkhalifa/Desktop/Utilitaire_Python/Text_Python.txt') as file_object:
...     contents = file_object.readline()
...     for line in file_object:
...             line = "<seg>" + line + "</seg>"
...             print(line, end='')
...
<seg>very simple flowers with a single row of petals which took up very little space and were
</seg><seg>no bother. They would appear one morning in the grass, and then fade the same evening.</seg>>>>

Comme vous pouvez le voir, la première ligne du fichier n'est pas prise en compte.

> Ce code ne fonctionne pas parce que je suis mauvais en Python, à vous de voir comment le corriger. > > ```python > with open('test.org') as file_object: > contents = file_object.read() > for line in file_object: > line = "<seg>" + line + "</seg>" > print(line, end='') > > ``` @Anand a réussi avec la méthode ci-dessus, mais cela n'a pas fonctionné pour @Leodelaune et moi. Voici donc les deux méthodes que nous avons utilisées et les résultats obtenus. ```python >>> f = open(r'/Users/sirinebenhadjkhalifa/Desktop/Utilitaire_Python/Text_Python.txt') >>> contents = f.readline() >>> for line in f: ... line = "<seg>" + line + "</seg>" ... print(line, end='') ... <seg>very simple flowers with a single row of petals which took up very little space and were </seg><seg>no bother. They would appear one morning in the grass, and then fade the same evening.</seg>>>> ``` et ```python >>> with open(r'/Users/sirinebenhadjkhalifa/Desktop/Utilitaire_Python/Text_Python.txt') as file_object: ... contents = file_object.readline() ... for line in file_object: ... line = "<seg>" + line + "</seg>" ... print(line, end='') ... <seg>very simple flowers with a single row of petals which took up very little space and were </seg><seg>no bother. They would appear one morning in the grass, and then fade the same evening.</seg>>>> ``` Comme vous pouvez le voir, la première ligne du fichier n'est pas prise en compte.
ciri closed this issue 2023-05-10 16:02:45 +02:00
Collaborator

J'ai trouvé une alternative qui prend en compte la première ligne du fichier :

with open(r'C:\Users\anand\Desktop\serpent\test.txt') as file_object:
        contents = file_object.readlines()
        for line in contents:
                line = "<seg>" + line + "</seg>"
                print(line, end='')
J'ai trouvé une alternative qui prend en compte la première ligne du fichier : ```python with open(r'C:\Users\anand\Desktop\serpent\test.txt') as file_object: contents = file_object.readlines() for line in contents: line = "<seg>" + line + "</seg>" print(line, end='')
ciri reopened this issue 2023-05-10 16:05:47 +02:00
Collaborator

Ce code ne fonctionne pas parce que je suis mauvais en Python, à vous de voir comment le corriger.

with open('test.org') as file_object:
    contents = file_object.read()
    for line in file_object: 
        line = "<seg>" + line + "</seg>"
        print(line, end='')

@Anand a réussi avec la méthode ci-dessus, mais cela n'a pas fonctionné pour @Leodelaune et moi.

Le code ci-dessus tel quel n'imprimera rien. Je pense que le succès de Anand provient plutôt du code qu'il a présenté dans son commentaire avec l'alternative qui tient compte de la première ligne du fichier.

Voici donc les deux méthodes que nous avons utilisées et les résultats obtenus.

Je ne cite que la deuxième parce qu'elle est à préférer et, qu'à l'exception du changement de nom de la variable f à file_object les deux méthodes sont en fait identiques en ce qui concerne le code qui lit le fichier, modifie les lignes, et les imprime.

La seule — mais importante ! — différence entre les deux tentatives est la façon d'ouvrir le fichier. Les lignes suivantes

f = open(r'chemin/et/nom/du/fichier')

et

with open(r'chemin/et/nom/du/fichier') as f

font exactement la même chose : elles ouvrent le fichier dans un object appelé f.
L'importante différence, c'est que si l'on utilise f = open(), pour ouvrir le fichier, il faut ensuite le fermer manuellement avec f.close() une fois qu'on a finit de l'utiliser.

Par contre, la construction with open() as ferme automatiquement le fichier une fois qu'on a fini de l'utiliser. C'est (en simplifiant) la raison principale pour laquelle l'utilisation de withest préférable.

>>> with open(r'/Users/sirinebenhadjkhalifa/Desktop/Utilitaire_Python/Text_Python.txt') as file_object:
...     contents = file_object.readline()
...     for line in file_object:
...             line = "<seg>" + line + "</seg>"
...             print(line, end='')
...
<seg>very simple flowers with a single row of petals which took up very little space and were
</seg><seg>no bother. They would appear one morning in the grass, and then fade the same evening.</seg>>>>

Comme vous pouvez le voir, la première ligne du fichier n'est pas prise en compte.

Si on vérifie les valeurs dans les variables, on constate que pour les deux méthodes, la première ligne du fichier se trouve dans la variable contents.

Le cœur des deux tentatives est identique :

1  contents = file_object.readline()
2  for line in file_object:
3      line = "<seg>" + line + "</seg>"
4      print(line, end='')

Une fois le fichier ouvert, voici ce qui ce passe dans ce code :

  1. La première ligne du fichier est lue dans la variable contents, qui prend le type string.
  2. La boucle commence une itération à partir de la deuxième ligne du fichier jusqu'à la dernière ligne.
  3. À chaque itération, les balises <seg>et </seg> sont ajoutées respectivement en début et en fin de ligne.
  4. Chacune des lignes est affichée à l'écran sans retour de ligne.

Comparons ce code à celui de la solution présentée par Anand :

J'ai trouvé une alternative qui prend en compte la première ligne du fichier :

with open(r'C:\Users\anand\Desktop\serpent\test.txt') as file_object:
        contents = file_object.readlines()
        for line in contents:
                line = "<seg>" + line + "</seg>"
                print(line, end='')

Le cœur de la solution ici diffère légèrement :

1  contents = file_object.readlines()
2  for line in contents:
3      line = "<seg> +  line + </seg>
4      print(line, end='')

Dans ce code, les deux premières lignes ne font pas la même chose que dans celui des tentatives précédentes :

  1. Toutes les lignes du fichier sont lues dans la variable contents, qui prend le type list.
  2. La boucle commence une itération sur la liste contents, à partir du début de la liste.

Les lignes 3 et 4 sont identiques.

Dernière observation pour aujourd'hui, parce qu'il se fait tard ici.

Avez-vous remarquez qu'entre le code de Jean-Christophe, Sirine et Anand, trois différentes méthodes (au sens Python) ont été utilisées pour lire le contenu du fichier ?

  • @brandelune : contents = file_object.read()
  • @ciri : contents = file_object.readline()
  • @Anand : contents = file_object.readlines()

Je vous laisse un peu de temps pour faire des recherches au sujet des différences entre ces méthodes, et demain j'expliquerai pourquoi le code de Jean-Christophe échoue, celui de Sirine n'affiche pas la première ligne, et celui de Anand fonctionne.

> > Ce code ne fonctionne pas parce que je suis mauvais en Python, à vous de voir comment le corriger. > > > > ```python > > with open('test.org') as file_object: > > contents = file_object.read() > > for line in file_object: > > line = "<seg>" + line + "</seg>" > > print(line, end='') > > > > ``` > > @Anand a réussi avec la méthode ci-dessus, mais cela n'a pas fonctionné pour @Leodelaune et moi. Le code ci-dessus tel quel n'imprimera rien. Je pense que le succès de Anand provient plutôt du code qu'il a présenté dans son commentaire avec l'alternative qui tient compte de la première ligne du fichier. > Voici donc les deux méthodes que nous avons utilisées et les résultats obtenus. Je ne cite que la deuxième parce qu'elle est à préférer et, qu'à l'exception du changement de nom de la variable `f` à `file_object` les deux méthodes sont en fait identiques en ce qui concerne le code qui lit le fichier, modifie les lignes, et les imprime. La seule — mais importante ! — différence entre les deux tentatives est la façon d'ouvrir le fichier. Les lignes suivantes ```python f = open(r'chemin/et/nom/du/fichier') ``` et ```python with open(r'chemin/et/nom/du/fichier') as f ``` font exactement la même chose : elles ouvrent le fichier dans un object appelé `f`. L'importante différence, c'est que si l'on utilise `f = open()`, pour ouvrir le fichier, il faut ensuite le fermer manuellement avec `f.close()` une fois qu'on a finit de l'utiliser. Par contre, la construction `with open() as` ferme automatiquement le fichier une fois qu'on a fini de l'utiliser. C'est (en simplifiant) la raison principale pour laquelle l'utilisation de `with`est préférable. > ```python > >>> with open(r'/Users/sirinebenhadjkhalifa/Desktop/Utilitaire_Python/Text_Python.txt') as file_object: > ... contents = file_object.readline() > ... for line in file_object: > ... line = "<seg>" + line + "</seg>" > ... print(line, end='') > ... > <seg>very simple flowers with a single row of petals which took up very little space and were > </seg><seg>no bother. They would appear one morning in the grass, and then fade the same evening.</seg>>>> > ``` > Comme vous pouvez le voir, la première ligne du fichier n'est pas prise en compte. Si on vérifie les valeurs dans les variables, on constate que pour les deux méthodes, la première ligne du fichier se trouve dans la variable `contents`. Le cœur des deux tentatives est identique : ```python 1 contents = file_object.readline() 2 for line in file_object: 3 line = "<seg>" + line + "</seg>" 4 print(line, end='') ``` Une fois le fichier ouvert, voici ce qui ce passe dans ce code : 1. La première ligne du fichier est lue dans la variable `contents`, qui prend le type _string_. 2. La boucle commence une itération à partir de la deuxième ligne du fichier jusqu'à la dernière ligne. 3. À chaque itération, les balises `<seg>`et `</seg>` sont ajoutées respectivement en début et en fin de ligne. 4. Chacune des lignes est affichée à l'écran sans retour de ligne. Comparons ce code à celui de la solution présentée par Anand : > J'ai trouvé une alternative qui prend en compte la première ligne du fichier : > > ```python > with open(r'C:\Users\anand\Desktop\serpent\test.txt') as file_object: > contents = file_object.readlines() > for line in contents: > line = "<seg>" + line + "</seg>" > print(line, end='') Le cœur de la solution ici diffère légèrement : ```python 1 contents = file_object.readlines() 2 for line in contents: 3 line = "<seg> + line + </seg> 4 print(line, end='') ``` Dans ce code, les deux premières lignes ne font pas la même chose que dans celui des tentatives précédentes : 1. Toutes les lignes du fichier sont lues dans la variable `contents`, qui prend le type _list_. 2. La boucle commence une itération sur la liste `contents`, à partir du début de la liste. Les lignes 3 et 4 sont identiques. Dernière observation pour aujourd'hui, parce qu'il se fait tard ici. Avez-vous remarquez qu'entre le code de Jean-Christophe, Sirine et Anand, trois différentes méthodes (au sens Python) ont été utilisées pour lire le contenu du fichier ? - @brandelune : `contents = file_object.read()` - @ciri : `contents = file_object.readline()` - @Anand : `contents = file_object.readlines()` Je vous laisse un peu de temps pour faire des recherches au sujet des différences entre ces méthodes, et demain j'expliquerai pourquoi le code de Jean-Christophe échoue, celui de Sirine n'affiche pas la première ligne, et celui de Anand fonctionne.
Author
Owner

Avez-vous remarquez qu'entre le code de Jean-Christophe, Sirine et Anand, trois différentes méthodes (au sens Python) ont été utilisées pour lire le contenu du fichier ?

  • @brandelune : contents = file_object.read()
  • @ciri : contents = file_object.readline()
  • @Anand : contents = file_object.readlines()

Je vous laisse un peu de temps pour faire des recherches au sujet des différences entre ces méthodes, et demain j'expliquerai pourquoi le code de Jean-Christophe échoue, celui de Sirine n'affiche pas la première ligne, et celui de Anand fonctionne.

  • La méthode contents = file_object.read() lit le fichier en séparant les caractères. Voici un extrait de ce que j'obtiens :
<seg>I</seg><seg> </seg><seg>s</seg><seg>o</seg><seg>o</seg><seg>n</seg><seg> </seg><seg>l</seg><seg>e</seg><seg>a</seg><seg>r</seg><seg>n</seg><seg>e</seg><seg>d</seg><seg> </seg><seg>m</seg><seg>o</seg><seg>r</seg><seg>e</seg><seg>
[...]

La commande .read() permet normalement de lire le fichier entier, mais ici, je crois que Python considère chaque caractère comme une ligne.

  • La méthode contents = file_object.readline() ne prend en compte que la première ligne, mais en toujours en séparant les caractères :
<seg>I</seg><seg> </seg><seg>s</seg><seg>o</seg><seg>o</seg><seg>n</seg><seg> </seg><seg>l</seg><seg>e</seg><seg>a</seg><seg>r</seg><seg>n</seg><seg>e</seg><seg>d</seg><seg> </seg><seg>m</seg><seg>o</seg><seg>r</seg><seg>e</seg><seg> </seg><seg>a</seg><seg>b</seg><seg>o</seg><seg>u</seg><seg>t</seg><seg> </seg><seg>t</seg><seg>h</seg><seg>i</seg><seg>s</seg><seg> </seg><seg>f</seg><seg>l</seg><seg>o</seg><seg>w</seg><seg>e</seg><seg>r</seg><seg>.</seg><seg>
</seg>

La commande .readline() ne permet de lire qu'une seule ligne : à partir d'un caractère de début de ligne jusqu'à un caractère de fin de ligne.

  • Enfin, avec contents = file_object.readlines() on obtient quelque chose de plus correcte :
<seg>I soon learned more about this flower.
</seg><seg>On the little prince's planet there had always been very simple flowers with a single row of petals which took up very little space and were no bother.
</seg><seg>They would appear one morning in the grass, and then fade the same evening.
</seg>

Cette méthode fonctionne puisqu'elle indique qu'il faut lire toutes les lignes du fichier.


Pendant notre réunion de ce matin, nous avons essayé de décaler la balise fermante </seg> pour qu’elle se trouve à la fin de chaque ligne plutôt qu'au début de la ligne suivante.

Premier essai :

with open(r'/Users/sirinebenhadjkhalifa/Desktop/Utilitaire_Python/Text_Python.txt') as file_object:
    contents = file_object.readlines()
    for line in contents:
        line ="<seg>" + line + "</seg>"
        print(line, end='\n')

Résultat :

<seg>I soon learned more about this flower.
</seg>
<seg>On the little prince's planet there had always been very simple flowers with a single row of petals which took up very little space and were no bother.
</seg>
<seg>They would appear one morning in the grass, and then fade the same evening.
</seg>

Ici, la balise </seg> est seule sur une ligne. Nous avons donc utilisé la méthode strip:

with open(r'/Users/sirinebenhadjkhalifa/Desktop/Utilitaire_Python/Text_Python.txt') as file_object:
    contents = file_object.readlines()
    for line in contents:
        line ="<seg>" + line.strip() + "</seg>"
        print(line, end='\n')

Et ça fonctionne :

<seg>I soon learned more about this flower.</seg>
<seg>On the little prince's planet there had always been very simple flowers with a single row of petals which took up very little space and were no bother.</seg>
<seg>They would appear one morning in the grass, and then fade the same evening.</seg>

Prochaine étape :

→ Créer une TMX monolingue

> Avez-vous remarquez qu'entre le code de Jean-Christophe, Sirine et Anand, trois différentes méthodes (au sens Python) ont été utilisées pour lire le contenu du fichier ? > > - @brandelune : `contents = file_object.read()` > - @ciri : `contents = file_object.readline()` > - @Anand : `contents = file_object.readlines()` > > Je vous laisse un peu de temps pour faire des recherches au sujet des différences entre ces méthodes, et demain j'expliquerai pourquoi le code de Jean-Christophe échoue, celui de Sirine n'affiche pas la première ligne, et celui de Anand fonctionne. - La méthode `contents = file_object.read()` lit le fichier en séparant les caractères. Voici un extrait de ce que j'obtiens : ```python <seg>I</seg><seg> </seg><seg>s</seg><seg>o</seg><seg>o</seg><seg>n</seg><seg> </seg><seg>l</seg><seg>e</seg><seg>a</seg><seg>r</seg><seg>n</seg><seg>e</seg><seg>d</seg><seg> </seg><seg>m</seg><seg>o</seg><seg>r</seg><seg>e</seg><seg> [...] ``` La commande `.read()` permet normalement de lire le fichier entier, mais ici, je crois que Python considère chaque caractère comme une ligne. - La méthode `contents = file_object.readline()` ne prend en compte que la première ligne, mais en toujours en séparant les caractères : ```python <seg>I</seg><seg> </seg><seg>s</seg><seg>o</seg><seg>o</seg><seg>n</seg><seg> </seg><seg>l</seg><seg>e</seg><seg>a</seg><seg>r</seg><seg>n</seg><seg>e</seg><seg>d</seg><seg> </seg><seg>m</seg><seg>o</seg><seg>r</seg><seg>e</seg><seg> </seg><seg>a</seg><seg>b</seg><seg>o</seg><seg>u</seg><seg>t</seg><seg> </seg><seg>t</seg><seg>h</seg><seg>i</seg><seg>s</seg><seg> </seg><seg>f</seg><seg>l</seg><seg>o</seg><seg>w</seg><seg>e</seg><seg>r</seg><seg>.</seg><seg> </seg> ``` La commande `.readline()` ne permet de lire qu'une seule ligne : à partir d'un caractère de début de ligne jusqu'à un caractère de fin de ligne. - Enfin, avec `contents = file_object.readlines()` on obtient quelque chose de plus correcte : ```python <seg>I soon learned more about this flower. </seg><seg>On the little prince's planet there had always been very simple flowers with a single row of petals which took up very little space and were no bother. </seg><seg>They would appear one morning in the grass, and then fade the same evening. </seg> ``` Cette méthode fonctionne puisqu'elle indique qu'il faut lire **toutes les lignes** du fichier. ----- Pendant notre réunion de ce matin, nous avons essayé de décaler la balise fermante `</seg>` pour qu’elle se trouve à la fin de chaque ligne plutôt qu'au début de la ligne suivante. Premier essai : ```python with open(r'/Users/sirinebenhadjkhalifa/Desktop/Utilitaire_Python/Text_Python.txt') as file_object: contents = file_object.readlines() for line in contents: line ="<seg>" + line + "</seg>" print(line, end='\n') ``` Résultat : ```python <seg>I soon learned more about this flower. </seg> <seg>On the little prince's planet there had always been very simple flowers with a single row of petals which took up very little space and were no bother. </seg> <seg>They would appear one morning in the grass, and then fade the same evening. </seg> ``` Ici, la balise `</seg>` est seule sur une ligne. Nous avons donc utilisé la méthode `strip`: ```python with open(r'/Users/sirinebenhadjkhalifa/Desktop/Utilitaire_Python/Text_Python.txt') as file_object: contents = file_object.readlines() for line in contents: line ="<seg>" + line.strip() + "</seg>" print(line, end='\n') ``` Et ça fonctionne : ```python <seg>I soon learned more about this flower.</seg> <seg>On the little prince's planet there had always been very simple flowers with a single row of petals which took up very little space and were no bother.</seg> <seg>They would appear one morning in the grass, and then fade the same evening.</seg> ``` Prochaine étape : → Créer une TMX monolingue
Collaborator

Ouvrir des fichiers avec Python

Voici l'explication promise pour le code qui ne fonctionne pas.

Je vais regrouper le code des tentatives de Jean-Christophe et de Sirine parce que la cause du problème est la même dans les deux cas. Je vais aussi répondre aux observations et résulats décrits par Sirine entre mes deux commentaires.

Les méthodes read() et readline()

# Tentative de Jean-Christophe, qui n'affiche rien.

1  contents = file_object.read()
2  for line in file_object: 
3      line = "<seg>" + line + "</seg>"
4      print(line, end='')

# Tentative de Sirine, qui n'affiche pas la première ligne.
1  contents = file_object.readline()
2  for line in file_object:
3      line = "<seg>" + line + "</seg>"
4      print(line, end='')

Le problème de l'affichage provient du fait que quand Python lit un fichier, il utiliser un pointeur pour garder sa place (un peu comme un signet qu'on place dans un livre, ou comme un personne qui suit le texte du doigt en lisant).

Quand on ouvre le fichier, le pointeur est au tout début et se déplace au fur et à mesure qu'on lit le contenu.

Dans le code de Jean-Christophe, la méthode read() lit tout le contenu du fichier, et le pointeur se trouve à la fin du fichier, où il n'y a plus rien, lorsqu'on entre dans la boucle.

  • La méthode contents = file_object.read() lit le fichier en séparant les caractères. Voici un extrait de ce que j'obtiens :
<seg>I</seg><seg> </seg><seg>s</seg><seg>o</seg><seg>o</seg><seg>n</seg><seg> </seg><seg>l</seg><seg>e</seg><seg>a</seg><seg>r</seg><seg>n</seg><seg>e</seg><seg>d</seg><seg> </seg><seg>m</seg><seg>o</seg><seg>r</seg><seg>e</seg><seg>
[...]

La commande .read() permet normalement de lire le fichier entier, mais ici, je crois que Python considère chaque caractère comme une ligne.

Pas tout à fait. La méthode read() lit bel et bien le fichier entier, mais elle le lit comme une seule (longue) chaîne de caractères (string). Quand il procède à une itération sur un chaîne de caractères, Python lit un caractère à la fois. Vous pouvez le constater avec un exemple banal :

string = "chaîne"
for char in string:
    print(char)

qui donne le résultat suivant :

c
h
a
î
n
e

Si vous modifiez ce code banal pour ajouter les <seg> et </seg> et les afficher sans sauts de lignes comme dans la tentative originale, vous obtiendrez un <seg> et </seg> avant et après chaque lettre.

Dans le code de Sirine, la méthode readline() lit la première ligne du fichier, et place le pointeur à la deuxième ligne, où il se trouve lorsqu'on entre dans la boucle. Par conséquent, l'affichage commence à la deuxième ligne du fichier.

  • La méthode contents = file_object.readline() ne prend en compte que la première ligne, mais en toujours en séparant les caractères :

Même chose que ci-dessus. La ligne est lue comme une chaîne de caractères, et c'est l'itération qui modifie un caractère à la fois.

N'oubliez pas que le nom de la variable line n'est utile qu'à la personne qui écrit ou modifie le code, et n'a pas de sens pour Python. Les méthodes .read()et .readline() créent toutes deux un chaîne de caractères, et la boucle fait une itération sur chacun des éléments de cette chaîne, et donc sur un caractère à la fois. Si vous mettez un print(contents) avant la boucle, Python vous affichera soit tout le texte du fichier (pour .read()), soit sa première ligne (pour .readline()).

Ces deux premières tentatives présentent aussi la particularité de lire le fichier (ou sa première ligne) dans la variable contents, mais de faire une itération directement sur l'objet fichier file_object. Si le seul but est d'afficher les lignes sans faire de manipulation supplémentaire, on pourrait faire l'itération directement sur l'objet fichier sans s'embêter de la variable contents :

for line in file_object.read(): 
    line = "<seg>" + line + "</seg>"
    print(line, end='')

On obtient exatement le même résultat, avec les <seg> et </seg> avant et après chaque caractère puisque la boucle opère encore et toujours sur une chaîne de caractères.

La méthode readlines()

  • Enfin, avec contents = file_object.readlines() on obtient quelque chose de plus correcte :
<seg>I soon learned more about this flower.
</seg><seg>On the little prince's planet there had always been very simple flowers with a single row of petals which took up very little space and were no bother.
</seg><seg>They would appear one morning in the grass, and then fade the same evening.
</seg>

Cette méthode fonctionne puisqu'elle indique qu'il faut lire toutes les lignes du fichier.

La grande différence avec les méthodes read() et readline(), c'est que la méthode readlines() crée une liste (au sens de la structure de données « list » en Python), dont chacun des éléments est une chaîne de caractères correspondant à une ligne du fichier.

Le code proposé par Anand crée donc dans la variable contents une liste qui contient chacune des lignes du fichier, et fait une itération sur chacun des éléments de cette liste pour y ajouter <seg> et </seg> au début et à la fin. Puisque l'itération ne se fait pas directement sur la chaîne même, on obtient un résultat correct où l'on crée une nouvelle chaîne de caractères qui commence par « <seg> », suivi de toute la chaîne de caractères contenant le texte de la ligne, et terminée par « </seg> ».


Pendant notre réunion de ce matin, nous avons essayé de décaler la balise fermante </seg> pour qu’elle se trouve à la fin de chaque ligne plutôt qu'au début de la ligne suivante.

Premier essai :

with open(r'/Users/sirinebenhadjkhalifa/Desktop/Utilitaire_Python/Text_Python.txt') as file_object:
    contents = file_object.readlines()
    for line in contents:
        line ="<seg>" + line + "</seg>"
        print(line, end='\n')

Résultat :

<seg>I soon learned more about this flower.
</seg>
<seg>On the little prince's planet there had always been very simple flowers with a single row of petals which took up very little space and were no bother.
</seg>
<seg>They would appear one morning in the grass, and then fade the same evening.
</seg>

La raison pour laquelle la balise fermante </seg> se trouve au début de la ligne suivante est que la méthode readlines() conserve le saut de ligne dans la chaîne de caractère.

Votre solution avec la méthode strip() fonctionne bien avec un simple fichier, mais nécessite une précaution. Cette méthode n'élimine pas que les sauts de ligne si on ne précise pas le caratères à enlever de la chaîne. Par défaut, la méthode enlève tous les caractères d'espace blanc (whitespace characters) en début ou en fin de chaîne, ce qui pourrait avoir des conséquences imprévues avec un fichier plus complexe. Il serait peut-être plus prudent de préciser explicitement le saut de ligne aved strip('\n')… sauf qu'il faut ensuite songer aux différences entre Windows (qui utilise '\r\n') et les autres systèmes qui utilisent '\n' pour représenter le saut de ligne.

En passant, le end='\n' dans la ligne print(line, end='\n') n'est pas strictement nécessaire puisque que c'est la valeur par défaut. Bien sûr, il n'y a aucun mal à le rendre explicite.

Ma solution

Tel que promis, je vous présente aussi la solution que j'utiliserais :

from pathlib import Path

fichier = Path(r'/Users/sirinebenhadjkhalifa/Desktop/Utilitaire_Python/Text_Python.txt')

with open(fichier) as file_object:
    contents = file_object.read().splitlines()
    for line in contents:
        line ="<seg>" + line + "</seg>"
        print(line)

J'avais mentionné pathlib dans un message précédent. Je préfère l'utiliser à un chemin inscrit directement en chaîne de caractère parce qu'il simplifie l'expansion du code pour, par exemple, sauvegarder le fichier modifier dans le même répertoire ou le répertoire parent, ou faire d'autres manipulations sur le nom du fichier ou sur les répertoires.

Dans la partie principale du code, la ligne importante est la suivante :

contents = file_object.read().splitlines()

En enchaînant la méthode splitlines() à la méthode read() j'obtiens, à l'instar de la méthode readlines() une liste qui contient chacune des lignes du fichier. L'important différence, c'est que la méthode splitlines() ne conserve pas le saut de ligne.

Si on regarde la valeur de la chaîne de caractère pour la première ligne, on obtient :

I soon learned more about this flower.\n

avec readlines(), et

I soon learned more about this flower.

avec splitlines().

L'utilisation de .read().splitlines() nous permet donc d'éviter d'avoir à traiter chacune des lignes une à la fois pour en retire le saut de ligne, et nous évite aussi d'avoir à s'embêter avec les éventuelles différences entre les fichiers créés sous Windows et ceux créés sous d'autres systèmes.


J'espère que ces explications sont suffisamment claires. Sinon, n'hésitez pas à poser des questions.

# Ouvrir des fichiers avec Python Voici l'explication promise pour le code qui ne fonctionne pas. Je vais regrouper le code des tentatives de Jean-Christophe et de Sirine parce que la cause du problème est la même dans les deux cas. Je vais aussi répondre aux observations et résulats décrits par Sirine entre mes deux commentaires. ## Les méthodes `read()` et `readline()` ```python # Tentative de Jean-Christophe, qui n'affiche rien. 1 contents = file_object.read() 2 for line in file_object: 3 line = "<seg>" + line + "</seg>" 4 print(line, end='') # Tentative de Sirine, qui n'affiche pas la première ligne. 1 contents = file_object.readline() 2 for line in file_object: 3 line = "<seg>" + line + "</seg>" 4 print(line, end='') ``` Le problème de l'affichage provient du fait que quand Python lit un fichier, il utiliser un _pointeur_ pour garder sa place (un peu comme un signet qu'on place dans un livre, ou comme un personne qui suit le texte du doigt en lisant). Quand on ouvre le fichier, le pointeur est au tout début et se déplace au fur et à mesure qu'on lit le contenu. Dans le code de Jean-Christophe, la méthode `read()` lit tout le contenu du fichier, et le pointeur se trouve à la fin du fichier, où il n'y a plus rien, lorsqu'on entre dans la boucle. > - La méthode `contents = file_object.read()` lit le fichier en séparant les caractères. Voici un extrait de ce que j'obtiens : > ```python > <seg>I</seg><seg> </seg><seg>s</seg><seg>o</seg><seg>o</seg><seg>n</seg><seg> </seg><seg>l</seg><seg>e</seg><seg>a</seg><seg>r</seg><seg>n</seg><seg>e</seg><seg>d</seg><seg> </seg><seg>m</seg><seg>o</seg><seg>r</seg><seg>e</seg><seg> > [...] > ``` > La commande `.read()` permet normalement de lire le fichier entier, mais ici, je crois que Python considère chaque caractère comme une ligne. > Pas tout à fait. La méthode `read()` lit bel et bien le fichier entier, mais elle le lit comme une seule (longue) chaîne de caractères (_string_). Quand il procède à une itération sur un chaîne de caractères, Python lit un caractère à la fois. Vous pouvez le constater avec un exemple banal : ```python string = "chaîne" for char in string: print(char) ``` qui donne le résultat suivant : ``` c h a î n e ``` Si vous modifiez ce code banal pour ajouter les `<seg>` et `</seg>` et les afficher sans sauts de lignes comme dans la tentative originale, vous obtiendrez un `<seg>` et `</seg>` avant et après chaque lettre. Dans le code de Sirine, la méthode `readline()` lit la première ligne du fichier, et place le pointeur à la deuxième ligne, où il se trouve lorsqu'on entre dans la boucle. Par conséquent, l'affichage commence à la deuxième ligne du fichier. > - La méthode `contents = file_object.readline()` ne prend en compte que la première ligne, mais en toujours en séparant les caractères : Même chose que ci-dessus. La ligne est lue comme une chaîne de caractères, et c'est l'itération qui modifie un caractère à la fois. N'oubliez pas que le nom de la variable `line` n'est utile qu'à la personne qui écrit ou modifie le code, et n'a pas de sens pour Python. Les méthodes `.read()`et `.readline()` créent toutes deux un chaîne de caractères, et la boucle fait une itération sur chacun des éléments de cette chaîne, et donc sur un caractère à la fois. Si vous mettez un `print(contents)` avant la boucle, Python vous affichera soit tout le texte du fichier (pour `.read()`), soit sa première ligne (pour `.readline()`). Ces deux premières tentatives présentent aussi la particularité de lire le fichier (ou sa première ligne) dans la variable `contents`, mais de faire une itération directement sur l'objet fichier `file_object`. Si le seul but est d'afficher les lignes sans faire de manipulation supplémentaire, on pourrait faire l'itération directement sur l'objet fichier sans s'embêter de la variable `contents` : ```python for line in file_object.read(): line = "<seg>" + line + "</seg>" print(line, end='') ``` On obtient exatement le même résultat, avec les `<seg>` et `</seg>` avant et après chaque caractère puisque la boucle opère encore et toujours sur une chaîne de caractères. ## La méthode `readlines()` > - Enfin, avec `contents = file_object.readlines()` on obtient quelque chose de plus correcte : > ```python > <seg>I soon learned more about this flower. > </seg><seg>On the little prince's planet there had always been very simple flowers with a single row of petals which took up very little space and were no bother. > </seg><seg>They would appear one morning in the grass, and then fade the same evening. > </seg> > ``` > Cette méthode fonctionne puisqu'elle indique qu'il faut lire **toutes les lignes** du fichier. La grande différence avec les méthodes `read()` et `readline()`, c'est que la méthode `readlines()` crée une ***liste*** (au sens de la structure de données « _list_ » en Python), dont chacun des éléments est une chaîne de caractères correspondant à une ligne du fichier. Le code proposé par Anand crée donc dans la variable `contents` une liste qui contient chacune des lignes du fichier, et fait une itération sur chacun des ***éléments*** de cette liste pour y ajouter `<seg>` et `</seg>` au début et à la fin. Puisque l'itération ne se fait pas directement sur la chaîne même, on obtient un résultat correct où l'on crée une nouvelle chaîne de caractères qui commence par « \<seg\> », suivi de toute la chaîne de caractères contenant le texte de la ligne, et terminée par « \</seg\> ». ----- > Pendant notre réunion de ce matin, nous avons essayé de décaler la balise fermante `</seg>` pour qu’elle se trouve à la fin de chaque ligne plutôt qu'au début de la ligne suivante. > > Premier essai : > ```python > with open(r'/Users/sirinebenhadjkhalifa/Desktop/Utilitaire_Python/Text_Python.txt') as file_object: > contents = file_object.readlines() > for line in contents: > line ="<seg>" + line + "</seg>" > print(line, end='\n') > ``` > Résultat : > ``` > <seg>I soon learned more about this flower. > </seg> > <seg>On the little prince's planet there had always been very simple flowers with a single row of petals which took up very little space and were no bother. > </seg> > <seg>They would appear one morning in the grass, and then fade the same evening. > </seg> > ``` La raison pour laquelle la balise fermante `</seg>` se trouve au début de la ligne suivante est que la méthode `readlines()` conserve le saut de ligne dans la chaîne de caractère. Votre solution avec la méthode `strip()` fonctionne bien avec un simple fichier, mais nécessite une précaution. Cette méthode n'élimine pas que les sauts de ligne si on ne précise pas le caratères à enlever de la chaîne. Par défaut, la méthode enlève tous les caractères d'espace blanc (_whitespace characters_) en début ou en fin de chaîne, ce qui pourrait avoir des conséquences imprévues avec un fichier plus complexe. Il serait peut-être plus prudent de préciser explicitement le saut de ligne aved `strip('\n')`… sauf qu'il faut ensuite songer aux différences entre Windows (qui utilise `'\r\n'`) et les autres systèmes qui utilisent `'\n'` pour représenter le saut de ligne. En passant, le `end='\n'` dans la ligne `print(line, end='\n')` n'est pas strictement nécessaire puisque que c'est la valeur par défaut. Bien sûr, il n'y a aucun mal à le rendre explicite. ## Ma solution Tel que promis, je vous présente aussi la solution que j'utiliserais : ```python from pathlib import Path fichier = Path(r'/Users/sirinebenhadjkhalifa/Desktop/Utilitaire_Python/Text_Python.txt') with open(fichier) as file_object: contents = file_object.read().splitlines() for line in contents: line ="<seg>" + line + "</seg>" print(line) ``` J'avais mentionné `pathlib` dans un message précédent. Je préfère l'utiliser à un chemin inscrit directement en chaîne de caractère parce qu'il simplifie l'expansion du code pour, par exemple, sauvegarder le fichier modifier dans le même répertoire ou le répertoire parent, ou faire d'autres manipulations sur le nom du fichier ou sur les répertoires. Dans la partie principale du code, la ligne importante est la suivante : ```python contents = file_object.read().splitlines() ``` En enchaînant la méthode `splitlines()` à la méthode `read()` j'obtiens, à l'instar de la méthode `readlines()` une ***liste*** qui contient chacune des lignes du fichier. L'important différence, c'est que la méthode `splitlines()` ne conserve *pas* le saut de ligne. Si on regarde la valeur de la chaîne de caractère pour la première ligne, on obtient : ``` I soon learned more about this flower.\n ``` avec `readlines()`, et ``` I soon learned more about this flower. ``` avec `splitlines()`. L'utilisation de `.read().splitlines()` nous permet donc d'éviter d'avoir à traiter chacune des lignes une à la fois pour en retire le saut de ligne, et nous évite aussi d'avoir à s'embêter avec les éventuelles différences entre les fichiers créés sous Windows et ceux créés sous d'autres systèmes. ----- J'espère que ces explications sont suffisamment claires. Sinon, n'hésitez pas à poser des questions.
Collaborator

Mon code pour faire un semblant de TMX :

from pathlib import Path

fichier = Path(r'C:\Users\anand\Desktop\serpent\test2.txt')

with open(fichier) as file_object:
        contents = file_object.read().splitlines()
        print("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
        print("<!DOCTYPE tmx SYSTEM \"tmx14.dtd\">")
        print("<tmx version=\"1.4\">")
        print("<header creationtool=\"OmegaT\" o-tmf=\"OmegaT TMX\" adminlang=\"EN-US\" datatype=\"plaintext\" creationtoolversion=\"5.7.1_0_c3206253\" segtype=\"sentence\" srclang=\"en\"/>")
        print("<body>")
        for line in contents:
                line = "<tu>" + "<tuv xml:lang=\"fr\">" + "<seg>" + line.strip() + "</seg>" + "</tuv>" + "</tu>"
                print(line, end='\n')

print("</body>")
print("</tmx>")

Mon code pour faire un semblant de TMX : ```python from pathlib import Path fichier = Path(r'C:\Users\anand\Desktop\serpent\test2.txt') with open(fichier) as file_object: contents = file_object.read().splitlines() print("<?xml version=\"1.0\" encoding=\"UTF-8\"?>") print("<!DOCTYPE tmx SYSTEM \"tmx14.dtd\">") print("<tmx version=\"1.4\">") print("<header creationtool=\"OmegaT\" o-tmf=\"OmegaT TMX\" adminlang=\"EN-US\" datatype=\"plaintext\" creationtoolversion=\"5.7.1_0_c3206253\" segtype=\"sentence\" srclang=\"en\"/>") print("<body>") for line in contents: line = "<tu>" + "<tuv xml:lang=\"fr\">" + "<seg>" + line.strip() + "</seg>" + "</tuv>" + "</tu>" print(line, end='\n') print("</body>") print("</tmx>")
Collaborator

@Anand

Votre code de « semblant de TMX » produit un fichier TMX valide sur le plan syntaxique.

Toutefois, le choix du code de langue dans "xml:lang = fr" m'intrigue (principalement parce que j'ai le texte de Sirine en tête comme fichier texte). Est-ce que vous utilisez plutôt un fichier test avec des phrases en français ?

Petite astuce Python : on peut éviter d'avoir à mettre des caratères d'échappement pour les guillemets en choisissant judicieusement entre les guillemets simples (apostrophes) et les guillemets doubles. Une chaîne de caractères délimitée par des guillements simples peut contenir des guillemets doubles sans qu'il soit nécessaire de les échapper (et vice versa).

La première fonction print(), par exemple, peut être réécrite de la façon suivante :

print('<?xml version="1.0" encoding="UTF-8"?>')

Vous pouvez appliquer le même principe aux autres lignes qui utilisent la fonction print(), ou encore a tout autre endroit où vous définissez un chaîne de caractères.

Et il va falloir les définir ailleurs tôt ou tard. L'affichage à l'écran, c'est utile pour le retour visuel immédiat, mais ça manque de permanence ! 😁

Vous aller devoir songer à comment sauvegarder cette TMX dans un fichier.

Et ensuite, je pense que Jean-Christophe vous parlera de la distinction entre traiter un fichier qui ne contient que du texte ordinaire et un fichier XML…

@Anand Votre code de « semblant de TMX » produit un fichier TMX valide sur le plan syntaxique. Toutefois, le choix du code de langue dans "xml:lang = fr" m'intrigue (principalement parce que j'ai le texte de Sirine en tête comme fichier texte). Est-ce que vous utilisez plutôt un fichier test avec des phrases en français ? Petite astuce Python : on peut éviter d'avoir à mettre des caratères d'échappement pour les guillemets en choisissant judicieusement entre les guillemets simples (apostrophes) et les guillemets doubles. Une chaîne de caractères délimitée par des guillements simples peut contenir des guillemets doubles sans qu'il soit nécessaire de les échapper (et vice versa). La première fonction `print()`, par exemple, peut être réécrite de la façon suivante : ```python print('<?xml version="1.0" encoding="UTF-8"?>') ``` Vous pouvez appliquer le même principe aux autres lignes qui utilisent la fonction `print()`, ou encore a tout autre endroit où vous définissez un chaîne de caractères. Et il va falloir les définir ailleurs tôt ou tard. L'affichage à l'écran, c'est utile pour le retour visuel immédiat, mais ça manque de permanence ! 😁 Vous aller devoir songer à comment sauvegarder cette TMX dans un fichier. Et ensuite, je pense que Jean-Christophe vous parlera de la distinction entre traiter un fichier qui ne contient que du texte ordinaire et un fichier XML…
Collaborator

Vous aller devoir songer à comment sauvegarder cette TMX dans un fichier.

Et ensuite, je pense que Jean-Christophe vous parlera de la distinction entre traiter un fichier qui ne contient que du texte ordinaire et un fichier XML…

Ce sont 2 thèmes qu'on a abordés hier en session. Pour jeudi, on doit donc trouver :

  • comment créer un fichier TMX valide
  • comment faire une TMX bilingue à partir de 2 fichiers
  • comme l'enregistrer dans un fichier autonome

et d'ici la fin mai on va explorer :

  • comment créer une GUI simple pour choisir les fichiers
  • comment localiser la GUI
> Vous aller devoir songer à comment sauvegarder cette TMX dans un fichier. > > Et ensuite, je pense que Jean-Christophe vous parlera de la distinction entre traiter un fichier qui ne contient que du texte ordinaire et un fichier XML… Ce sont 2 thèmes qu'on a abordés hier en session. Pour jeudi, on doit donc trouver : - comment créer un fichier TMX valide - comment faire une TMX bilingue à partir de 2 fichiers - comme l'enregistrer dans un fichier autonome et d'ici la fin mai on va explorer : - comment créer une GUI simple pour choisir les fichiers - comment localiser la GUI
Author
Owner

Voici ce que nous avons réussi mettre en place durant la réunion de ce matin :

from pathlib import Path

source = Path(r'/Users/sirinebenhadjkhalifa/Desktop/Utilitaire_Python/Source.txt')
cible = Path(r'/Users/sirinebenhadjkhalifa/Desktop/Utilitaire_Python/Cible.txt')

with open(source) as contenu_source, open (cible) as contenu_cible:
    tuv_source = contenu_source.read().splitlines()
    tuv_cible = contenu_cible.read().splitlines()
    print('<?xml version="1.0" encoding="UTF-8"?>')
    print('<!DOCTYPE tmx SYSTEM "tmx14.dtd">')
    print('<tmx version="1.4">')
    print('<header creationtool="OmegaT" o-tmf="OmegaT TMX" adminlang="EN-US" datatype="plaintext" creationtoolversion="5.7.1_0_c3206253" segtype="sentence" srclang="en"/>')
    print('<body>')
    for seg_source, seg_cible in zip(tuv_source, tuv_cible):
        seg_source = '<tu>' + '<tuv xml:lang="en">' + '<seg>' + seg_source.strip() + '</seg>' + '</tuv>'
        seg_cible = '<tuv xml:lang="fr">' + '<seg>' + seg_cible.strip() + '</seg>' + '</tuv>' + '</tu>'
        print(seg_source, seg_cible, end='\n')
        
    print('</body>')
    print('</tmx>')

Résultat :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tmx SYSTEM "tmx14.dtd">
<tmx version="1.4">
<header creationtool="OmegaT" o-tmf="OmegaT TMX" adminlang="EN-US" datatype="plaintext" creationtoolversion="5.7.1_0_c3206253" segtype="sentence" srclang="en"/>
<body>
<tu><tuv xml:lang="en"><seg>I soon learned more about this flower.</seg></tuv> <tuv xml:lang="fr"><seg>Jappris bien vite à mieux connaître cette fleur.</seg></tuv></tu>
<tu><tuv xml:lang="en"><seg>On the little prince's planet there had always been very simple flowers with a single row of petals which took up very little space and were no bother.</seg></tuv> <tuv xml:lang="fr"><seg>Il y avait toujours eu, sur la planète du petit prince, des fleurs très simples, ornées d’un seul rang de pétales, et qui ne tenaient point de place, et qui ne dérangeaient personne.</seg></tuv></tu>
<tu><tuv xml:lang="en"><seg>They would appear one morning in the grass, and then fade the same evening.</seg></tuv> <tuv xml:lang="fr"><seg>Elles apparaissaient un matin dans lherbe, et puis elles séteignaient le soir.</seg></tuv></tu>
<tu><tuv xml:lang="en"><seg>But one day, from a seed blown from no one knew where, a new flower had come up; and the little prince had watched very closely over this small sprout which was not like any other small sprouts on his planet.</seg></tuv> <tuv xml:lang="fr"><seg>Mais celle- avait germé un jour, dune graine apportée don ne sait , et le petit prince avait surveillé de très près cette brindille qui ne ressemblait pas aux autres brindilles.</seg></tuv></tu>
<tu><tuv xml:lang="en"><seg>It might, you see, have been a new kind of baobab.</seg></tuv> <tuv xml:lang="fr"><seg>Ça pouvait être un nouveau genre de baobab.</seg></tuv></tu>
</body>
</tmx>

J'ai utilisé la fonction zip() pour créer une sorte de boucle. Maintenant, il faut essayer de l'enregistrer dans un fichier autonome.

Voici ce que nous avons réussi mettre en place durant la réunion de ce matin : ```python from pathlib import Path source = Path(r'/Users/sirinebenhadjkhalifa/Desktop/Utilitaire_Python/Source.txt') cible = Path(r'/Users/sirinebenhadjkhalifa/Desktop/Utilitaire_Python/Cible.txt') with open(source) as contenu_source, open (cible) as contenu_cible: tuv_source = contenu_source.read().splitlines() tuv_cible = contenu_cible.read().splitlines() print('<?xml version="1.0" encoding="UTF-8"?>') print('<!DOCTYPE tmx SYSTEM "tmx14.dtd">') print('<tmx version="1.4">') print('<header creationtool="OmegaT" o-tmf="OmegaT TMX" adminlang="EN-US" datatype="plaintext" creationtoolversion="5.7.1_0_c3206253" segtype="sentence" srclang="en"/>') print('<body>') for seg_source, seg_cible in zip(tuv_source, tuv_cible): seg_source = '<tu>' + '<tuv xml:lang="en">' + '<seg>' + seg_source.strip() + '</seg>' + '</tuv>' seg_cible = '<tuv xml:lang="fr">' + '<seg>' + seg_cible.strip() + '</seg>' + '</tuv>' + '</tu>' print(seg_source, seg_cible, end='\n') print('</body>') print('</tmx>') ``` Résultat : ```python <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE tmx SYSTEM "tmx14.dtd"> <tmx version="1.4"> <header creationtool="OmegaT" o-tmf="OmegaT TMX" adminlang="EN-US" datatype="plaintext" creationtoolversion="5.7.1_0_c3206253" segtype="sentence" srclang="en"/> <body> <tu><tuv xml:lang="en"><seg>I soon learned more about this flower.</seg></tuv> <tuv xml:lang="fr"><seg>J’appris bien vite à mieux connaître cette fleur.</seg></tuv></tu> <tu><tuv xml:lang="en"><seg>On the little prince's planet there had always been very simple flowers with a single row of petals which took up very little space and were no bother.</seg></tuv> <tuv xml:lang="fr"><seg>Il y avait toujours eu, sur la planète du petit prince, des fleurs très simples, ornées d’un seul rang de pétales, et qui ne tenaient point de place, et qui ne dérangeaient personne.</seg></tuv></tu> <tu><tuv xml:lang="en"><seg>They would appear one morning in the grass, and then fade the same evening.</seg></tuv> <tuv xml:lang="fr"><seg>Elles apparaissaient un matin dans l’herbe, et puis elles s’éteignaient le soir.</seg></tuv></tu> <tu><tuv xml:lang="en"><seg>But one day, from a seed blown from no one knew where, a new flower had come up; and the little prince had watched very closely over this small sprout which was not like any other small sprouts on his planet.</seg></tuv> <tuv xml:lang="fr"><seg>Mais celle-là avait germé un jour, d’une graine apportée d’on ne sait où, et le petit prince avait surveillé de très près cette brindille qui ne ressemblait pas aux autres brindilles.</seg></tuv></tu> <tu><tuv xml:lang="en"><seg>It might, you see, have been a new kind of baobab.</seg></tuv> <tuv xml:lang="fr"><seg>Ça pouvait être un nouveau genre de baobab.</seg></tuv></tu> </body> </tmx> ``` J'ai utilisé la fonction `zip()` pour créer une sorte de boucle. Maintenant, il faut essayer de l'enregistrer dans un fichier autonome.
Collaborator

Bravo. Je ne connaissais pas la fonction zip(). Ça nous aurait simplifié la vie l'an dernier...

Cet article explique la fonction en profondeur :
https://realpython.com/python-zip-function/

Avec ça, il nous reste à explorer la validation XML des seg. Et pour ceci, j'ai trouvé ce lien :
https://wiki.python.org/moin/EscapingXml

Pour l'interface graphique, j'ai trouvé ça :
https://www.blog.pythonlibrary.org/2021/09/29/create-gui/

Au plaisir de lire votre code lundi !

Jean-Christophe

Bravo. Je ne connaissais pas la fonction `zip()`. Ça nous aurait simplifié la vie l'an dernier... Cet article explique la fonction en profondeur : https://realpython.com/python-zip-function/ Avec ça, il nous reste à explorer la validation XML des `seg`. Et pour ceci, j'ai trouvé ce lien : https://wiki.python.org/moin/EscapingXml Pour l'interface graphique, j'ai trouvé ça : https://www.blog.pythonlibrary.org/2021/09/29/create-gui/ Au plaisir de lire votre code lundi ! Jean-Christophe
Collaborator

Bravo. Je ne connaissais pas la fonction zip(). Ça nous aurait simplifié la vie l'an dernier...

Je l'avais pourtant utilisé dans mon remaniement du script de l'an dernier quand tu l'avais présenté sur OmegaT-as-a-Book

Et bravo à tout le monde de l'avoir trouvée et appliquée. C'est la meilleure façon de grouper les bons éléments ensembles quand on veut combiner les éléments correspondants de deux (ou même plusieurs) listes.

Attention toutefois à la longueur des listes. Dans un projet un peu plus ambitieux, il faudra songer à la possibilité que l'une des listes soit plus longue que l'autre (ou les autres) et décider comment traiter de tels cas.

Avec ça, il nous reste à explorer la validation XML des seg. Et pour ceci, j'ai trouvé ce lien :
https://wiki.python.org/moin/EscapingXml

J'aurais cru que pour produire le fichier XML tu aurais plutôt choisi un des modules ici :
https://docs.python.org/3/library/xml.html

(Ils ont l'avantage d'être déjà disponible dans une installation Python standard.)

Pour la validation, est-ce qu'on parle de valider que le XML soit bien formé et valide sur le plan syntaxique, ou de vérifier la conformité avec un DTD ?

Dans le premier cas, on peut apparemment utiliser SAX.
Dans le deuxième, il faudra installer une bibliothèque tierce comme lxml ou xmlschema.

Voici un article long et très complet sur les analyseurs XML disponibles en Python :
https://realpython.com/python-xml-parser/

À titre d'information, j'utilise lxml pour tout mes besoins XML en Python, et je recommande cette bibliothèques si vous avez l'intention de continuez à faire du codage dans cette veine à moyen ou long terme.

Pour le projet en cours, les modules déjà installés avec Python sont suffisant, surtout si vous préférez éviter d'avoir à installer des bibliothèques tierces pour le moment (si on ne valide pas la conformité au DTD).

Pour l'interface graphique, j'ai trouvé ça :
https://www.blog.pythonlibrary.org/2021/09/29/create-gui/

Toujours dans l'optique de ne pas avoir à installer une bibliothèque tierce, Python contient déjà des modules pour le GUI :
https://docs.python.org/3/library/tkinter.html

Et voici un tutoriel dont la section 6 sur les dialogues et les menus sera d'un intérêt particulier si on veut seulement afficher une boîte de dialogue pour demander à l'utilisateur de choisir un fichier.

Toutefois, si le but est de créer une interface graphique un peu plus complète et jolie, la bibliothèque wxPython présentée dans l'article trouvé par Jean-Christophe sera probablement un meilleur choix.


Et voilà ! Mesdames et messieurs, faites vos choix ! 😸

Je vais regarder vos solutions avec intérêt !

> Bravo. Je ne connaissais pas la fonction `zip()`. Ça nous aurait simplifié la vie l'an dernier... Je l'avais pourtant utilisé dans mon remaniement du script de l'an dernier quand tu l'avais présenté sur _OmegaT-as-a-Book_… Et bravo à tout le monde de l'avoir trouvée et appliquée. C'est la meilleure façon de grouper les bons éléments ensembles quand on veut combiner les éléments correspondants de deux (ou même plusieurs) listes. Attention toutefois à la longueur des listes. Dans un projet un peu plus ambitieux, il faudra songer à la possibilité que l'une des listes soit plus longue que l'autre (ou les autres) et décider comment traiter de tels cas. > Avec ça, il nous reste à explorer la validation XML des `seg`. Et pour ceci, j'ai trouvé ce lien : > https://wiki.python.org/moin/EscapingXml J'aurais cru que pour produire le fichier XML tu aurais plutôt choisi un des modules ici : https://docs.python.org/3/library/xml.html (Ils ont l'avantage d'être déjà disponible dans une installation Python standard.) Pour la validation, est-ce qu'on parle de valider que le XML soit bien formé et valide sur le plan syntaxique, ou de vérifier la conformité avec un DTD ? Dans le premier cas, on peut apparemment utiliser [SAX](https://www.oreilly.com/library/view/python-cookbook/0596001673/ch12s02.html). Dans le deuxième, il faudra installer une bibliothèque tierce comme [`lxml`](https://lxml.de/) ou [`xmlschema`](https://github.com/sissaschool/xmlschema). Voici un article long et très complet sur les analyseurs XML disponibles en Python : https://realpython.com/python-xml-parser/ À titre d'information, j'utilise `lxml` pour tout mes besoins XML en Python, et je recommande cette bibliothèques si vous avez l'intention de continuez à faire du codage dans cette veine à moyen ou long terme. Pour le projet en cours, les modules déjà installés avec Python sont suffisant, surtout si vous préférez éviter d'avoir à installer des bibliothèques tierces pour le moment (si on ne valide pas la conformité au DTD). > Pour l'interface graphique, j'ai trouvé ça : > https://www.blog.pythonlibrary.org/2021/09/29/create-gui/ Toujours dans l'optique de ne pas avoir à installer une bibliothèque tierce, Python contient déjà des modules pour le GUI : https://docs.python.org/3/library/tkinter.html Et voici un [`tutoriel`](https://www.pythontutorial.net/tkinter/) dont la section 6 sur les dialogues et les menus sera d'un intérêt particulier si on veut seulement afficher une boîte de dialogue pour demander à l'utilisateur de choisir un fichier. Toutefois, si le but est de créer une interface graphique un peu plus complète et jolie, la bibliothèque `wxPython` présentée dans l'article trouvé par Jean-Christophe sera probablement un meilleur choix. ----- Et voilà ! Mesdames et messieurs, faites vos choix ! 😸 Je vais regarder vos solutions avec intérêt !
Collaborator

Bravo. Je ne connaissais pas la fonction zip(). Ça nous aurait simplifié la vie l'an dernier...

Je l'avais pourtant utilisé dans mon remaniement du script de l'an dernier quand tu l'avais présenté sur OmegaT-as-a-Book

Hahaha ! Tu surestimes ma capacité à me souvenir d'un truc qui s'est passé plus tard que la semaine précédente...

Avec ça, il nous reste à explorer la validation XML des seg. Et pour ceci, j'ai trouvé ce lien :
https://wiki.python.org/moin/EscapingXml

J'aurais cru que pour produire le fichier XML tu aurais plutôt choisi un des modules ici :
https://docs.python.org/3/library/xml.html

J'avais trouvé Element Tree mais dans le tutoriel je n'ai pas trouvé comment convertir une chaîne arbitraire en truc qui passe en XML, or, c'est juste ce dont on a besoin ici.

Et j'ai eu la flemme de chercher plus loin.

Pour la validation, est-ce qu'on parle de valider que le XML soit bien formé et valide sur le plan syntaxique, ou de vérifier la conformité avec un DTD ?

L'idée, c'est soit d'utiliser une librairie XML comme on a fait l'an dernier, soit de faire un truc à la main comme ici, mais en faisant attention au contenu textuel. Il n'y a pas de validation au-delà de ça.

Pour l'interface graphique, j'ai trouvé ça :
https://www.blog.pythonlibrary.org/2021/09/29/create-gui/

En fait, je pensais en particulier à PySimpleGUI.
https://realpython.com/pysimplegui-python/

Toutefois, si le but est de créer une interface graphique un peu plus complète et jolie, la bibliothèque wxPython présentée dans l'article trouvé par Jean-Christophe sera probablement un meilleur choix.

L'idée c'est d'avoir une GUI pour sélectionner les fichiers en entrée, les langues, et l'emplacement du fichier de sortie.

Puis de passer tout ça à la moulinette gettext pour un faire un truc localisable, et donc le localiser...

Je vais regarder vos solutions avec intérêt !

Moi aussi :-)

> > Bravo. Je ne connaissais pas la fonction `zip()`. Ça nous aurait simplifié la vie l'an dernier... > > Je l'avais pourtant utilisé dans mon remaniement du script de l'an dernier quand tu l'avais présenté sur _OmegaT-as-a-Book_… Hahaha ! Tu surestimes ma capacité à me souvenir d'un truc qui s'est passé plus tard que la semaine précédente... > > Avec ça, il nous reste à explorer la validation XML des `seg`. Et pour ceci, j'ai trouvé ce lien : > > https://wiki.python.org/moin/EscapingXml > > J'aurais cru que pour produire le fichier XML tu aurais plutôt choisi un des modules ici : > https://docs.python.org/3/library/xml.html J'avais trouvé Element Tree mais dans le tutoriel je n'ai pas trouvé comment convertir une chaîne arbitraire en truc qui passe en XML, or, c'est juste ce dont on a besoin ici. Et j'ai eu la flemme de chercher plus loin. > Pour la validation, est-ce qu'on parle de valider que le XML soit bien formé et valide sur le plan syntaxique, ou de vérifier la conformité avec un DTD ? L'idée, c'est soit d'utiliser une librairie XML comme on a fait l'an dernier, soit de faire un truc à la main comme ici, mais en faisant attention au contenu textuel. Il n'y a pas de validation au-delà de ça. > > Pour l'interface graphique, j'ai trouvé ça : > > https://www.blog.pythonlibrary.org/2021/09/29/create-gui/ En fait, je pensais en particulier à PySimpleGUI. https://realpython.com/pysimplegui-python/ > Toutefois, si le but est de créer une interface graphique un peu plus complète et jolie, la bibliothèque `wxPython` présentée dans l'article trouvé par Jean-Christophe sera probablement un meilleur choix. L'idée c'est d'avoir une GUI pour sélectionner les fichiers en entrée, les langues, et l'emplacement du fichier de sortie. Puis de passer tout ça à la moulinette gettext pour un faire un truc localisable, et donc le localiser... > Je vais regarder vos solutions avec intérêt ! Moi aussi :-)
Collaborator

Bravo. Je ne connaissais pas la fonction zip(). Ça nous aurait simplifié la vie l'an dernier...

Je l'avais pourtant utilisé dans mon remaniement du script de l'an dernier quand tu l'avais présenté sur OmegaT-as-a-Book

Hahaha ! Tu surestimes ma capacité à me souvenir d'un truc qui s'est passé plus tard que la semaine précédente...

En fait, j'ai triché. Je suis retourné voir mon code pour voir si je l'avais utilisée là. 😄

J'aurais cru que pour produire le fichier XML tu aurais plutôt choisi un des modules ici :
https://docs.python.org/3/library/xml.html

J'avais trouvé Element Tree mais dans le tutoriel je n'ai pas trouvé comment convertir une chaîne arbitraire en truc qui passe en XML, or, c'est juste ce dont on a besoin ici.

Avec ElementTree, ce n'est pas très compliqué. Dans notre cas :

  1. On crée l'arbre tmx.
  2. On crée les éléments et sous-éléments appropriés (et leurs attributs, au besoin).
  3. Quand on arrive aux sous-éléments<seg>, on leur assigne la valeur de la chaîne arbitraire correspondante.
  4. On sauvegarde le tout dans un fichier.

Pour la validation, est-ce qu'on parle de valider que le XML soit bien formé et valide sur le plan syntaxique, ou de vérifier la conformité avec un DTD ?

L'idée, c'est soit d'utiliser une librairie XML comme on a fait l'an dernier, soit de faire un truc à la main comme ici, mais en faisant attention au contenu textuel. Il n'y a pas de validation au-delà de ça.

Dans ce cas, les fonctions de ElementTree (ou autres modules XML) font presque tout le travail. Il suffit de préciser les noms et valeurs des éléments et des attributs que l'on veut mettre dans le fichier, et le module s'occupe de créer des éléments XML valides.

Il faut être un peu maso pour faire ça à la main ! 😨

Pour l'interface graphique, j'ai trouvé ça :
https://www.blog.pythonlibrary.org/2021/09/29/create-gui/

En fait, je pensais en particulier à PySimpleGUI.
https://realpython.com/pysimplegui-python/

Ah oui. Je l'ai toujours un peu en tête, mais je ne l'ai jamais vraiment essayé.

L'idée c'est d'avoir une GUI pour sélectionner les fichiers en entrée, les langues, et l'emplacement du fichier de sortie.

Intéressant. Rien de super compliqué, mais quand même un peu plus exigeant que de simplement faire apparaître une boîte de dialogue pour sélectionner les fichiers ou leur emplacement au moment voulu.

Puis de passer tout ça à la moulinette gettext pour un faire un truc localisable, et donc le localiser...

L'interface va faire po neuve !

> > > Bravo. Je ne connaissais pas la fonction `zip()`. Ça nous aurait simplifié la vie l'an dernier... > > > > Je l'avais pourtant utilisé dans mon remaniement du script de l'an dernier quand tu l'avais présenté sur _OmegaT-as-a-Book_… > > Hahaha ! Tu surestimes ma capacité à me souvenir d'un truc qui s'est passé plus tard que la semaine précédente... En fait, j'ai triché. Je suis retourné voir mon code pour voir si je l'avais utilisée là. 😄 > > J'aurais cru que pour produire le fichier XML tu aurais plutôt choisi un des modules ici : > > https://docs.python.org/3/library/xml.html > > J'avais trouvé Element Tree mais dans le tutoriel je n'ai pas trouvé comment convertir une chaîne arbitraire en truc qui passe en XML, or, c'est juste ce dont on a besoin ici. Avec ElementTree, ce n'est pas très compliqué. Dans notre cas : 1. On crée l'arbre `tmx`. 2. On crée les éléments et sous-éléments appropriés (et leurs attributs, au besoin). 3. Quand on arrive aux sous-éléments`<seg>`, on leur assigne la valeur de la chaîne arbitraire correspondante. 4. On sauvegarde le tout dans un fichier. > > Pour la validation, est-ce qu'on parle de valider que le XML soit bien formé et valide sur le plan syntaxique, ou de vérifier la conformité avec un DTD ? > > L'idée, c'est soit d'utiliser une librairie XML comme on a fait l'an dernier, soit de faire un truc à la main comme ici, mais en faisant attention au contenu textuel. Il n'y a pas de validation au-delà de ça. Dans ce cas, les fonctions de ElementTree (ou autres modules XML) font presque tout le travail. Il suffit de préciser les noms et valeurs des éléments et des attributs que l'on veut mettre dans le fichier, et le module s'occupe de créer des éléments XML valides. Il faut être un peu maso pour faire ça à la main ! 😨 > > > Pour l'interface graphique, j'ai trouvé ça : > > > https://www.blog.pythonlibrary.org/2021/09/29/create-gui/ > > En fait, je pensais en particulier à PySimpleGUI. > https://realpython.com/pysimplegui-python/ Ah oui. Je l'ai toujours un peu en tête, mais je ne l'ai jamais vraiment essayé. > L'idée c'est d'avoir une GUI pour sélectionner les fichiers en entrée, les langues, et l'emplacement du fichier de sortie. Intéressant. Rien de super compliqué, mais quand même un peu plus exigeant que de simplement faire apparaître une boîte de dialogue pour sélectionner les fichiers ou leur emplacement au moment voulu. > Puis de passer tout ça à la moulinette gettext pour un faire un truc localisable, et donc le localiser... L'interface va faire po neuve !
Author
Owner
import xml.etree.ElementTree as ET
 
# This is the parent (root) tag
# onto which other tags would be
# created
tmx = ET.Element('tmx')
tmx.set('version', '1.4')
 
# Adding a subtag named `Opening`
# inside our root tag
header = ET.SubElement(tmx, 'header')
header.set('adminlang', 'en')

body = ET.SubElement(tmx, 'body')
tu = ET.SubElement(body, 'tu')

# Adding subtags under the `Opening`
# subtag
tuv1 = ET.SubElement(tu, 'tuv')
tuv2 = ET.SubElement(tu, 'tuv')
seg1 = ET.SubElement(tuv1, 'seg')
seg2 = ET.SubElement(tuv2, 'seg')
 
# Adding attributes to the tags under
# `items`
tuv1.set('xml:lang', 'fr')
tuv2.set('xml:lang', 'en')
 
# Adding text between the `E4` and `D5`
# subtag
seg1.text = "Je m'appelle & Sirine"
seg2.text = "My name < is Sirine"


 
# Converting the xml data to byte object,
# for allowing flushing data to file
# stream
ET.indent(tmx)
b_xml = ET.tostring(tmx)
 
# Opening a file under the name `items2.xml`,
# with operation mode `wb` (write + binary)
with open("22mai.tmx", "wb") as f:
    f.write(b_xml)
```python import xml.etree.ElementTree as ET # This is the parent (root) tag # onto which other tags would be # created tmx = ET.Element('tmx') tmx.set('version', '1.4') # Adding a subtag named `Opening` # inside our root tag header = ET.SubElement(tmx, 'header') header.set('adminlang', 'en') body = ET.SubElement(tmx, 'body') tu = ET.SubElement(body, 'tu') # Adding subtags under the `Opening` # subtag tuv1 = ET.SubElement(tu, 'tuv') tuv2 = ET.SubElement(tu, 'tuv') seg1 = ET.SubElement(tuv1, 'seg') seg2 = ET.SubElement(tuv2, 'seg') # Adding attributes to the tags under # `items` tuv1.set('xml:lang', 'fr') tuv2.set('xml:lang', 'en') # Adding text between the `E4` and `D5` # subtag seg1.text = "Je m'appelle & Sirine" seg2.text = "My name < is Sirine" # Converting the xml data to byte object, # for allowing flushing data to file # stream ET.indent(tmx) b_xml = ET.tostring(tmx) # Opening a file under the name `items2.xml`, # with operation mode `wb` (write + binary) with open("22mai.tmx", "wb") as f: f.write(b_xml) ```
Collaborator

Ce qu'on a fait aujourd'hui n'est pas trivial.

Prenez le temps de revoir comment toutes ces choses fonctionnent.

En particulier la structure suivante:

mon_objet_2 = mon_objet_1.UneFonction(des, arguments, ou, pas)

Ça veut dire :

  • on a un objet qui s'appelle mon_objet_1,
  • on lui applique la fonction UneFonction avec les arguments nécessaires,
  • et on met le résultat dans un autre objet qu'on a décidé d'appeler mon_objet_2.

Et on peut maintenant utiliser mon_objet_2 pour faire d'autres trucs.

Faites une ou deux réunions complémentaires d'ici jeudi pour bien échanger et tenter d'être à un niveau de compréhension proche.

Et pas de stress si c'est dur. Il faut juste s'assurer entre nous que ce n'est pas impossible.

Par ailleurs, il ne s'agit pas ici de savoir comment produire un code de ce type sans filet. Il s'agit juste de comprendre ce qu'on cherche, comment ça fonctionne et d'être capable de faire des copier-coller qui fonctionnent, petit à petit.

N'oubliez pas. Petit à petit. Il faut qu'à chaque nouvelle ligne ajoutée, vous ailliez du code qui fonctionne.

**Ce qu'on a fait aujourd'hui n'est pas trivial.** Prenez le temps de revoir comment toutes ces choses fonctionnent. En particulier la structure suivante: ```python mon_objet_2 = mon_objet_1.UneFonction(des, arguments, ou, pas) ``` Ça veut dire : - on a un objet qui s'appelle `mon_objet_1`, - on lui applique la fonction `UneFonction` avec les arguments nécessaires, - et on met le résultat dans un autre objet qu'on a décidé d'appeler `mon_objet_2`. Et on peut maintenant utiliser mon_objet_2 pour faire d'autres trucs. Faites une ou deux réunions complémentaires d'ici jeudi pour bien échanger et tenter d'être à un niveau de compréhension proche. Et pas de stress si c'est dur. Il faut juste s'assurer entre nous que ce n'est pas impossible. Par ailleurs, il ne s'agit pas ici de savoir comment produire un code de ce type sans filet. Il s'agit juste de comprendre ce qu'on cherche, comment ça fonctionne et d'être capable de faire des copier-coller qui fonctionnent, petit à petit. N'oubliez pas. **Petit à petit**. Il faut qu'à *chaque nouvelle ligne ajoutée*, vous ailliez du code qui fonctionne.
Collaborator

J'ai fusionné les deux codes pour obtenir ça :

from pathlib import Path
import xml.etree.ElementTree as ET

source = Path(r'C:\Users\anand\Desktop\serpent\test.txt')
target = Path(r'C:\Users\anand\Desktop\serpent\test2.txt')

with open(source) as source_file, open(target) as target_file:
    source_tuv = source_file.read().splitlines()
    target_tuv = target_file.read().splitlines()
    with open("Aligner.tmx", "wb") as f:
        tmx = ET.Element('tmx')
        tmx.set('version', '1.4')
        header = ET.SubElement(tmx, 'header')
        header.set('adminlang', 'en')
        body = ET.SubElement(tmx, 'body')
        for(source_seg, target_seg) in zip(source_tuv, target_tuv):
            tu = ET.SubElement(body, 'tu')
            tuv1 = ET.SubElement(tu, 'tuv')
            tuv2 = ET.SubElement(tu, 'tuv')
            tuv1.set('xml:lang', 'fr')
            tuv2.set('xml:lang', 'en')
            seg1 = ET.SubElement(tuv1, 'seg')
            seg2 = ET.SubElement(tuv2, 'seg')
            seg1.text = source_seg.strip()
            seg2.text = target_seg.strip()
            ET.indent(tmx)
            a_xml = ET.tostring(tmx)

            
with open("Aligner.tmx", "wb") as f:            
    f.write(a_xml)

Ce qui me créer un fichier Aligner.tmx qui contient ça :

<tmx version="1.4">
  <header adminlang="en" />
  <body>
    <tu>
      <tuv xml:lang="fr">
        <seg>testons des phrases</seg>
      </tuv>
      <tuv xml:lang="en">
        <seg>let's test some sentences</seg>
      </tuv>
    </tu>
    <tu>
      <tuv xml:lang="fr">
        <seg>&#231;a peut para&#238;tre insens&#233; mais</seg>
      </tuv>
      <tuv xml:lang="en">
        <seg>that might seem foolish but</seg>
      </tuv>
    </tu>
    <tu>
      <tuv xml:lang="fr">
        <seg>la vie n'est-elle pas insens&#233;e en soi?</seg>
      </tuv>
      <tuv xml:lang="en">
        <seg>ain't life foolish in itself?</seg>
      </tuv>
    </tu>
    <tu>
      <tuv xml:lang="fr">
        <seg>a m&#233;diter</seg>
      </tuv>
      <tuv xml:lang="en">
        <seg>think about it</seg>
      </tuv>
    </tu>
  </body>
</tmx>

Ca m'a l'air correct, il reste la question du comment intégrer au début les lignes :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tmx SYSTEM "tmx14.dtd">
J'ai fusionné les deux codes pour obtenir ça : ```python from pathlib import Path import xml.etree.ElementTree as ET source = Path(r'C:\Users\anand\Desktop\serpent\test.txt') target = Path(r'C:\Users\anand\Desktop\serpent\test2.txt') with open(source) as source_file, open(target) as target_file: source_tuv = source_file.read().splitlines() target_tuv = target_file.read().splitlines() with open("Aligner.tmx", "wb") as f: tmx = ET.Element('tmx') tmx.set('version', '1.4') header = ET.SubElement(tmx, 'header') header.set('adminlang', 'en') body = ET.SubElement(tmx, 'body') for(source_seg, target_seg) in zip(source_tuv, target_tuv): tu = ET.SubElement(body, 'tu') tuv1 = ET.SubElement(tu, 'tuv') tuv2 = ET.SubElement(tu, 'tuv') tuv1.set('xml:lang', 'fr') tuv2.set('xml:lang', 'en') seg1 = ET.SubElement(tuv1, 'seg') seg2 = ET.SubElement(tuv2, 'seg') seg1.text = source_seg.strip() seg2.text = target_seg.strip() ET.indent(tmx) a_xml = ET.tostring(tmx) with open("Aligner.tmx", "wb") as f: f.write(a_xml) ``` Ce qui me créer un fichier Aligner.tmx qui contient ça : ```xml <tmx version="1.4"> <header adminlang="en" /> <body> <tu> <tuv xml:lang="fr"> <seg>testons des phrases</seg> </tuv> <tuv xml:lang="en"> <seg>let's test some sentences</seg> </tuv> </tu> <tu> <tuv xml:lang="fr"> <seg>&#231;a peut para&#238;tre insens&#233; mais</seg> </tuv> <tuv xml:lang="en"> <seg>that might seem foolish but</seg> </tuv> </tu> <tu> <tuv xml:lang="fr"> <seg>la vie n'est-elle pas insens&#233;e en soi?</seg> </tuv> <tuv xml:lang="en"> <seg>ain't life foolish in itself?</seg> </tuv> </tu> <tu> <tuv xml:lang="fr"> <seg>a m&#233;diter</seg> </tuv> <tuv xml:lang="en"> <seg>think about it</seg> </tuv> </tu> </body> </tmx> ``` Ca m'a l'air correct, il reste la question du comment intégrer au début les lignes : ```xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE tmx SYSTEM "tmx14.dtd"> ```
Collaborator

Le problème, c'est que vous appelez des fichiers test, mais que vous codez manuellement le fait qu'il n'y aura que 2 segments. 😓

Il faut aller plus loin dans l'intégration puisqu'il faut considérer un nombre arbitraire de lignes dans les fichiers et donc voir comment utiliser la partie zip du code de la semaine dernière. 😓

~~Le problème, c'est que vous appelez des fichiers test, mais que vous codez manuellement le fait qu'il n'y aura que 2 segments.~~ 😓 ~~Il faut aller plus loin dans l'intégration puisqu'il faut considérer un nombre arbitraire de lignes dans les fichiers et donc voir comment utiliser la partie `zip` du code de la semaine dernière.~~ 😓
Collaborator

Pour les déclarations, cherchez "declaration" et "doctype" dans la documentation de ElementTree.

Pour les déclarations, cherchez "declaration" et "doctype" dans la documentation de ElementTree.
Collaborator

Je pense que vous avez jeté de bonnes bases sur lesquelles poursuivre cet exercice, mais comme vous le savez sans doute, il reste encore du chemin à faire. 😀

Voici quelques observations sur vos derniers efforts :

  1. Attributs de l'élément <header>

    La spécification TMX en ligne ou en PDF indique comme « required attributes » les attributs suivants :

    • creationtool
    • creationtoolversion
    • segtype
    • o-tmf
    • adminlang
    • srclang
    • datatype

    Pour créer un fichier TMX valide, il vous faudra donc modifier votre code pour inclure tous ces attributs dans l'élément <header>.

    Pour ce faire, en fouillant dans la documentation, vous pourrez trouvez une façon plus simple que d'utiliser la méthode .set() pour chaque attribut individuellement. (Je ne connaissais pas cette méthode —merci ! Toutefois, elle semble plutôt servir à modifier un attribut dans un fichier XML qu'on lit et modifie un peu)

  2. Encodage

    Je vois des « &#231; » et des « &#238; » dans la sortie du code d'Anand. Il est possible de régler l'encodage pour obtenir une sortie qui ne bousille pas les caractères non-ASCII.

    (Un fichier XML devrait normalement être en 'utf-8' ou autre encodage Unicode qui présente les caratères correctement.)

  3. Déclaration et doctype

    La déclaration, c'est assez simple, mais pour une raison quelconque, avec xml.etree.ElementTree, il faut faire quelques acrobaties pour inclure le doctype.

    (Je pense que c'est parce que xml.etree.ElementTree est plus axée sur la lecture et la modification de fichiers XML existants que sur la création de nouveaux fichiers XML.)

  4. Problèmes d'organisation du code

    Je vois deux problèmes au niveau du code en soi :

    • Le fichier Aligner.tmx se fait ouvrir deux fois. Pourquoi ?

    • Imbrications inutiles :

      En Python, attention à l'indentation. Elle n'est pas que visuelle ! Il est facile d'oublier d'avancer ou de reculer au bon niveau d'indentation.

      Dans votre code, je vois :

      • un bloc de code qui s'exécute au sein du bloc précédent sans dépendre de processus en cours dans le premier bloc pour mener ses propres opérations
      • des commandes qui sont répétées inutilement dans une boucle

    Avec les cours fichiers tests utilisés pour le moment, on ne voit pas d'effet négatifs, mais si on appliquait le code à des fichiers contenant des centaines ou des milliers de lignes, la différence de performance va se faire sentir.

Jean-Christophe a parlé d'objets et de fonctions plus tôt, ainsi que de gérer un nombre arbitraire de lignes.

J'ai écrit un petit script qui utilise des fonctions pour lire un nombre arbitraire de fichiers contenant un nombre tout aussi arbitraire de lignes.

Pour vous donner quelques pistes, je vais vous présenter le processus que j'ai suivi, le squelette du script (sans code précis !), et les résultats que j'ai obtenu dans un message ultérieur.

Je pense que vous avez jeté de bonnes bases sur lesquelles poursuivre cet exercice, mais comme vous le savez sans doute, il reste encore du chemin à faire. :grinning: Voici quelques observations sur vos derniers efforts : 1. Attributs de l'élément `<header>` La spécification TMX [en ligne](https://www.gala-global.org/tmx-14b) ou [en PDF](https://uri.etsi.org/lis/002/v1.4.2/gs_LIS002v010402p.pdf) indique comme « required attributes » les attributs suivants : - creationtool - creationtoolversion - segtype - o-tmf - adminlang - srclang - datatype Pour créer un fichier TMX valide, il vous faudra donc modifier votre code pour inclure tous ces attributs dans l'élément `<header>`. Pour ce faire, en fouillant dans la documentation, vous pourrez trouvez une façon plus simple que d'utiliser la méthode `.set()` pour chaque attribut individuellement. (Je ne connaissais pas cette méthode —merci ! Toutefois, elle semble plutôt servir à modifier un attribut dans un fichier XML qu'on lit et modifie un peu) 2. Encodage Je vois des « `&#231;` » et des « `&#238;` » dans la sortie du code d'Anand. Il est possible de régler l'encodage pour obtenir une sortie qui ne bousille pas les caractères non-ASCII. (Un fichier XML devrait normalement être en 'utf-8' ou autre encodage Unicode qui présente les caratères correctement.) 3. Déclaration et doctype La déclaration, c'est assez simple, mais pour une raison quelconque, avec `xml.etree.ElementTree`, il faut faire quelques acrobaties pour inclure le doctype. (Je pense que c'est parce que `xml.etree.ElementTree` est plus axée sur la lecture et la modification de fichiers XML existants que sur la création de nouveaux fichiers XML.) 4. Problèmes d'organisation du code Je vois deux problèmes au niveau du code en soi : - Le fichier `Aligner.tmx` se fait ouvrir deux fois. Pourquoi ? - Imbrications inutiles : En Python, attention à l'indentation. Elle n'est pas que visuelle ! Il est facile d'oublier d'avancer ou de reculer au bon niveau d'indentation. Dans votre code, je vois : - un bloc de code qui s'exécute au sein du bloc précédent sans dépendre de processus en cours dans le premier bloc pour mener ses propres opérations - des commandes qui sont répétées inutilement dans une boucle Avec les cours fichiers tests utilisés pour le moment, on ne voit pas d'effet négatifs, mais si on appliquait le code à des fichiers contenant des centaines ou des milliers de lignes, la différence de performance va se faire sentir. Jean-Christophe a parlé d'_objets_ et de _fonctions_ plus tôt, ainsi que de gérer un nombre arbitraire de lignes. J'ai écrit un petit script qui utilise des fonctions pour lire un nombre arbitraire de fichiers contenant un nombre tout aussi arbitraire de lignes. Pour vous donner quelques pistes, je vais vous présenter le processus que j'ai suivi, le squelette du script (sans code précis !), et les résultats que j'ai obtenu dans un message ultérieur.
Collaborator

Avant d'entrer dans le vif du sujet, petit addendum à mon message précédent. Dans la section sur l'encodage, je n'avais pas remarqué que le site décodait et affichait correctement les caractères qui avaient attiré mon attention dans la sortie produite par le code d'Anand.

Vous aurez devinez que je parlais des codes &#231; et compagnie (maintenant aussi corrigés dans le commentaire lui-même).


Parlons maintenant du processus de création de script.

J'ai rédigé un article qui décrit ma démarche et présente le squelette de mon script ainsi que les résultats obtenus.

Puisqu'il est un peu long pour un commentaire dans un ticket, je l'ai plutôt mis dans une page du wiki.

Comme je le mentionne dans la conclusion, il ne s'agit que d'une approche possible parmi plusieures.

J'espère qu'elle vous sera utile comme piste pour poursuivre vos propres idées. Qui sait, peut-être trouverez-vous de meilleures solutions que la mienne !

Si vous avez des questions ou des commentaires, ne vous gênez pas !


Petite suggestion (à vérifier avec Jean-Christophe avant de procéder)

Je pense que vous arrivez à une étape de la création de l'utilitaire où il serait utile de créer un répertoire pour mettre votre code (et vos fichiers de test) sous contrôle de version (probablement en créant chacun votre propre branche).

Il vous sera plus facile de collaborer sur le code de cette façon et vous pourrez créer des tickets plus précis associés à votre projet Python pour les problèmes que vous allez rencontrez.

Avant d'entrer dans le vif du sujet, petit addendum à mon message précédent. Dans la section sur l'encodage, je n'avais pas remarqué que le site décodait et affichait correctement les caractères qui avaient attiré mon attention dans la sortie produite par le code d'Anand. Vous aurez devinez que je parlais des codes `&#231;` et compagnie (maintenant aussi corrigés dans le commentaire lui-même). --- Parlons maintenant du processus de création de script. J'ai rédigé un article qui décrit ma démarche et présente le squelette de mon script ainsi que les résultats obtenus. Puisqu'il est un peu long pour un commentaire dans un ticket, je l'ai plutôt mis dans une [page du wiki](https://forge.chapril.org/ciri/stage_2023/wiki/Exemple-de-cr%C3%A9ation-de-script-en-Python). Comme je le mentionne dans la conclusion, il ne s'agit que d'une approche possible parmi plusieures. J'espère qu'elle vous sera utile comme piste pour poursuivre vos propres idées. Qui sait, peut-être trouverez-vous de meilleures solutions que la mienne ! Si vous avez des questions ou des commentaires, ne vous gênez pas ! --- Petite suggestion (à vérifier avec Jean-Christophe avant de procéder) Je pense que vous arrivez à une étape de la création de l'utilitaire où il serait utile de créer un répertoire pour mettre votre code (et vos fichiers de test) sous contrôle de version (probablement en créant chacun votre propre branche). Il vous sera plus facile de collaborer sur le code de cette façon et vous pourrez créer des tickets plus précis associés à votre projet Python pour les problèmes que vous allez rencontrez.
Collaborator

Mise à jour du code :

from pathlib import Path
from lxml import etree as LX

source = Path(r'C:\Users\anand\Desktop\serpent\test.txt')
target = Path(r'C:\Users\anand\Desktop\serpent\test2.txt')
langattribute = LX.QName("http://www.w3.org/XML/1998/namespace", "lang")
original = LX.QName("o-tmf")

with open(source) as source_file, open(target) as target_file:
    source_tuv = source_file.read().splitlines()
    target_tuv = target_file.read().splitlines()
    tmx = LX.Element('tmx')
    tmx.set('version', '1.4')
    header = LX.SubElement(tmx, 'header', creationtool='AnandTools', creationtoolversion='1.0', adminlang='en-US', segtype='sentence', srclang='fr', datatype='plaintext')
    header.set(original, 'txt')
    body = LX.SubElement(tmx, 'body')
    for(source_seg, target_seg) in zip(source_tuv, target_tuv):
        tu = LX.SubElement(body, 'tu')
        tuv1 = LX.SubElement(tu, 'tuv')
        tuv2 = LX.SubElement(tu, 'tuv')
        tuv1.set(langattribute, "fr")
        tuv2.set(langattribute, "en")
        seg1 = LX.SubElement(tuv1, 'seg')
        seg2 = LX.SubElement(tuv2, 'seg')
        seg1.text = source_seg.strip()
        seg2.text = target_seg.strip()
        LX.indent(tmx)
        a_xml = LX.tostring(tmx, encoding='utf-8', method='xml', xml_declaration=True, doctype='<!DOCTYPE tmx SYSTEM "tmx14.dtd">')

            
with open("Aligner.tmx", "wb") as f:            
    f.write(a_xml)

On utilise lxml car il nous permet d'intégrer le doctype directement dans le .tostring().

On doit donc aussi utiliser des méthodes lxml sur tous les autres éléments, sinon la méthode .tostring() ne marche pas.

Mais la méthode .set() du lxml n'accepte pas l'attribut xml:lang à cause du ' : ', j'ai donc du contourner à l'aide de la méthode .QName().

J'ai ajouté les attributs du header directement dans le .SubElement() sauf pour o-tmf à cause du ' - '. J'ai donc aussi du contourner en l'ajoutant via la méthode .set() et .QName().

Ce code me créer un fichier Aligner.tmx qui contient :

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE tmx SYSTEM "tmx14.dtd">
<tmx version="1.4">
  <header creationtool="AnandTools" creationtoolversion="1.0" adminlang="en-US" segtype="sentence" srclang="fr" datatype="plaintext" o-tmf="txt"/>
  <body>
    <tu>
      <tuv xml:lang="fr">
        <seg>testons des phrases</seg>
      </tuv>
      <tuv xml:lang="en">
        <seg>let's test some sentences</seg>
      </tuv>
    </tu>
    <tu>
      <tuv xml:lang="fr">
        <seg>ça peut paraître insensé mais</seg>
      </tuv>
      <tuv xml:lang="en">
        <seg>that might seem foolish but</seg>
      </tuv>
    </tu>
    <tu>
      <tuv xml:lang="fr">
        <seg>la vie n'est-elle pas insensée en soi?</seg>
      </tuv>
      <tuv xml:lang="en">
        <seg>ain't life foolish in itself?</seg>
      </tuv>
    </tu>
    <tu>
      <tuv xml:lang="fr">
        <seg>a méditer</seg>
      </tuv>
      <tuv xml:lang="en">
        <seg>think about it</seg>
      </tuv>
    </tu>
  </body>
</tmx>
Mise à jour du code : ```python from pathlib import Path from lxml import etree as LX source = Path(r'C:\Users\anand\Desktop\serpent\test.txt') target = Path(r'C:\Users\anand\Desktop\serpent\test2.txt') langattribute = LX.QName("http://www.w3.org/XML/1998/namespace", "lang") original = LX.QName("o-tmf") with open(source) as source_file, open(target) as target_file: source_tuv = source_file.read().splitlines() target_tuv = target_file.read().splitlines() tmx = LX.Element('tmx') tmx.set('version', '1.4') header = LX.SubElement(tmx, 'header', creationtool='AnandTools', creationtoolversion='1.0', adminlang='en-US', segtype='sentence', srclang='fr', datatype='plaintext') header.set(original, 'txt') body = LX.SubElement(tmx, 'body') for(source_seg, target_seg) in zip(source_tuv, target_tuv): tu = LX.SubElement(body, 'tu') tuv1 = LX.SubElement(tu, 'tuv') tuv2 = LX.SubElement(tu, 'tuv') tuv1.set(langattribute, "fr") tuv2.set(langattribute, "en") seg1 = LX.SubElement(tuv1, 'seg') seg2 = LX.SubElement(tuv2, 'seg') seg1.text = source_seg.strip() seg2.text = target_seg.strip() LX.indent(tmx) a_xml = LX.tostring(tmx, encoding='utf-8', method='xml', xml_declaration=True, doctype='<!DOCTYPE tmx SYSTEM "tmx14.dtd">') with open("Aligner.tmx", "wb") as f: f.write(a_xml) ``` On utilise `lxml` car il nous permet d'intégrer le doctype directement dans le `.tostring()`. On doit donc aussi utiliser des méthodes `lxml` sur tous les autres éléments, sinon la méthode `.tostring()` ne marche pas. Mais la méthode `.set()` du `lxml` n'accepte pas l'attribut `xml:lang` à cause du ' : ', j'ai donc du contourner à l'aide de la méthode `.QName().` J'ai ajouté les attributs du header directement dans le `.SubElement()` sauf pour o-tmf à cause du ' - '. J'ai donc aussi du contourner en l'ajoutant via la méthode `.set()` et `.QName()`. Ce code me créer un fichier `Aligner.tmx` qui contient : ```xml <?xml version='1.0' encoding='utf-8'?> <!DOCTYPE tmx SYSTEM "tmx14.dtd"> <tmx version="1.4"> <header creationtool="AnandTools" creationtoolversion="1.0" adminlang="en-US" segtype="sentence" srclang="fr" datatype="plaintext" o-tmf="txt"/> <body> <tu> <tuv xml:lang="fr"> <seg>testons des phrases</seg> </tuv> <tuv xml:lang="en"> <seg>let's test some sentences</seg> </tuv> </tu> <tu> <tuv xml:lang="fr"> <seg>ça peut paraître insensé mais</seg> </tuv> <tuv xml:lang="en"> <seg>that might seem foolish but</seg> </tuv> </tu> <tu> <tuv xml:lang="fr"> <seg>la vie n'est-elle pas insensée en soi?</seg> </tuv> <tuv xml:lang="en"> <seg>ain't life foolish in itself?</seg> </tuv> </tu> <tu> <tuv xml:lang="fr"> <seg>a méditer</seg> </tuv> <tuv xml:lang="en"> <seg>think about it</seg> </tuv> </tu> </body> </tmx> ```
Collaborator

Ça avance ! J'aime bien le nouveau nom du « creationtool »  !

On utilise lxml car il nous permet d'intégrer le doctype directement dans le .tostring().

C'est effectivement la solution la plus simple pour ajouter le doctype.

Mais la méthode .set() du lxml n'accepte pas l'attribut xml:lang à cause du ' : ', j'ai donc du contourner à l'aide de la méthode .QName().

Belle trouvaille !
Je n'avais pas trouvé cette méthode la première fois que j'ai eu à résoudre ce problème.

J'ai ajouté les attributs du header directement dans le .SubElement()

Vous auriez pu faire la même chose pour la racine tmx juste avant. 😄

sauf pour o-tmf à cause du ' - '. J'ai donc aussi du contourner en l'ajoutant via la méthode .set() et .QName().

Astuce : on peut aussi passer les attributs sous forme de dictionnaire Python, et on peut utiliser des variables autant pour les clés que pour les valeurs. Par exemple :

dictionnaire = {'clé': 'valeur', variable: 'autre valeur',
                'autre clé': autre_variable, variable_clé: variable_valeur}

Quand il y a plusieurs attributes à ajouter à un élément, ça peut être plus pratique que d'utiliser la méthode .set().

Vous avez maintenant une sortie correcte, mais certains problèmes soulignés dans la version précédente sont toujours présents :

  • Le nombre de <tuv> par <tu>, et les langues qu'ils prennent, sont figés manuellement dans le code. (Est-ce simplement une mesure temporaire pour vérifier que la sortie est correcte avant de passer à la prochaine étape ?)

  • Les problèmes d'indentation sont toujours là. Dans la logique du programme :

    1. On ne manipule pas les fichiers texte après avoir récupéré les lignes qu'ils contiennent. Par conséquent, la création du document TMX devrait se faire à l'extérieur du bloc d'ouverture et de lecture des fichiers textes.

    2. Il n'est pas nécéssaire de (re)créer et formatter le document TMX chaque fois qu'on ajoute un élément <tu>. Le document TMX final devrait être créé une seule fois, après que toutes les phrases aient été jumelées et ajoutées à l'élément <body>.

    Ça n'empêche pas le code de fonctionner, mais ça pourrait causer des ennuis avec de plus gros fichiers ou au moment d'apporter des améliorations ou des ajouts au code.


Je vais attendre que Jean-Christophe me donne le feu verte, puis je vous présenterai mon propre code.

Ça avance ! J'aime bien le nouveau nom du « creationtool »  ! > On utilise `lxml` car il nous permet d'intégrer le doctype directement dans le `.tostring()`. C'est effectivement la solution la plus simple pour ajouter le doctype. > Mais la méthode `.set()` du `lxml` n'accepte pas l'attribut `xml:lang` à cause du ' : ', j'ai donc du contourner à l'aide de la méthode `.QName().` Belle trouvaille ! Je n'avais pas trouvé cette méthode la première fois que j'ai eu à résoudre ce problème. > J'ai ajouté les attributs du header directement dans le `.SubElement()` Vous auriez pu faire la même chose pour la racine `tmx` juste avant. :smile: > sauf pour o-tmf à cause du ' - '. J'ai donc aussi du contourner en l'ajoutant via la méthode `.set()` et `.QName()`. Astuce : on peut aussi passer les attributs sous forme de dictionnaire Python, et on peut utiliser des variables autant pour les clés que pour les valeurs. Par exemple : ```python dictionnaire = {'clé': 'valeur', variable: 'autre valeur', 'autre clé': autre_variable, variable_clé: variable_valeur} ``` Quand il y a plusieurs attributes à ajouter à un élément, ça peut être plus pratique que d'utiliser la méthode `.set()`. Vous avez maintenant une sortie correcte, mais certains problèmes soulignés dans la version précédente sont toujours présents : - Le nombre de `<tuv>` par `<tu>`, et les langues qu'ils prennent, sont figés manuellement dans le code. (Est-ce simplement une mesure temporaire pour vérifier que la sortie est correcte avant de passer à la prochaine étape ?) - Les problèmes d'indentation sont toujours là. Dans la logique du programme : 1. On ne manipule pas les fichiers texte après avoir récupéré les lignes qu'ils contiennent. Par conséquent, la création du document TMX devrait se faire à l'extérieur du bloc d'ouverture et de lecture des fichiers textes. 2. Il n'est pas nécéssaire de (re)créer et formatter le document TMX chaque fois qu'on ajoute un élément `<tu>`. Le document TMX final devrait être créé une seule fois, après que toutes les phrases aient été jumelées et ajoutées à l'élément `<body>`. Ça n'empêche pas le code de fonctionner, mais ça pourrait causer des ennuis avec de plus gros fichiers ou au moment d'apporter des améliorations ou des ajouts au code. --- Je vais attendre que Jean-Christophe me donne le feu verte, puis je vous présenterai mon propre code.
Collaborator
  • Le nombre de <tuv> par <tu>, et les langues qu'ils prennent, sont figés manuellement dans le code. (Est-ce simplement une mesure temporaire pour vérifier que la sortie est correcte avant de passer à la prochaine étape ?)

Pour les langues, on en a parlé hier.

Pour le nombre de <tuv>, il est figé à 2 parce qu'il y a 2 fichiers. Et comme on utilise zip par simplification, on se limite à 2 fichiers.

Avec 3+ fichiers, zip ne serait plus suffisant, parce qu'on ne pourrait plus se limiter au fichier le plus court des 3+.

Je vais attendre que Jean-Christophe me donne le feu verte, puis je vous présenterai mon propre code.

Attend le premier juin. Ça sera notre dernière séance.

> - Le nombre de `<tuv>` par `<tu>`, et les langues qu'ils prennent, sont figés manuellement dans le code. (Est-ce simplement une mesure temporaire pour vérifier que la sortie est correcte avant de passer à la prochaine étape ?) Pour les langues, on en a parlé hier. Pour le nombre de `<tuv>`, il est figé à 2 parce qu'il y a 2 fichiers. Et comme on utilise `zip` par simplification, on se limite à 2 fichiers. Avec 3+ fichiers, `zip` ne serait plus suffisant, parce qu'on ne pourrait plus se limiter au fichier le plus court des 3+. > Je vais attendre que Jean-Christophe me donne le feu verte, puis je vous présenterai mon propre code. Attend le premier juin. Ça sera notre dernière séance.
Collaborator

Pour le nombre de <tuv>, il est figé à 2 parce qu'il y a 2 fichiers. Et comme on utilise zip par simplification, on se limite à 2 fichiers.

Avec 3+ fichiers, zip ne serait plus suffisant, parce qu'on ne pourrait plus se limiter au fichier le plus court des 3+.

<voix Darth Vader>You underestimate the power of the dark zip</voix Darth Vader>

Je vais attendre que Jean-Christophe me donne le feu verte, puis je vous présenterai mon propre code.

Attend le premier juin. Ça sera notre dernière séance.

Parfait. Ça va me donner le temps de préparer une version « pseudo-pédagogique » ! 😀

> Pour le nombre de `<tuv>`, il est figé à 2 parce qu'il y a 2 fichiers. Et comme on utilise `zip` par simplification, on se limite à 2 fichiers. > > Avec 3+ fichiers, `zip` ne serait plus suffisant, parce qu'on ne pourrait plus se limiter au fichier le plus court des 3+. `<voix Darth Vader>`You underestimate the power of the dark `zip`…`</voix Darth Vader>` > > Je vais attendre que Jean-Christophe me donne le feu verte, puis je vous présenterai mon propre code. > > Attend le premier juin. Ça sera notre dernière séance. Parfait. Ça va me donner le temps de préparer une version « pseudo-pédagogique » ! 😀
Collaborator

Pour le nombre de <tuv>, il est figé à 2 parce qu'il y a 2 fichiers. Et comme on utilise zip par simplification, on se limite à 2 fichiers.

Avec 3+ fichiers, zip ne serait plus suffisant, parce qu'on ne pourrait plus se limiter au fichier le plus court des 3+.

<voix Darth Vader>You underestimate the power of the dark zip</voix Darth Vader>

Philippe, fais gaffe, il y a des références culturelles qui grillent 😂.

Je vais attendre que Jean-Christophe me donne le feu verte, puis je vous présenterai mon propre code.

Attend le premier juin. Ça sera notre dernière séance.

Parfait. Ça va me donner le temps de préparer une version « pseudo-pédagogique » ! 😀

Super !

> > Pour le nombre de `<tuv>`, il est figé à 2 parce qu'il y a 2 fichiers. Et comme on utilise `zip` par simplification, on se limite à 2 fichiers. > > > > Avec 3+ fichiers, `zip` ne serait plus suffisant, parce qu'on ne pourrait plus se limiter au fichier le plus court des 3+. > > `<voix Darth Vader>`You underestimate the power of the dark `zip`…`</voix Darth Vader>` Philippe, fais gaffe, il y a des références culturelles qui grillent 😂. > > > > Je vais attendre que Jean-Christophe me donne le feu verte, puis je vous présenterai mon propre code. > > > > Attend le premier juin. Ça sera notre dernière séance. > > Parfait. Ça va me donner le temps de préparer une version « pseudo-pédagogique » ! 😀 Super !
Collaborator

Code avec moins de problèmes d'indentations :

from pathlib import Path
from lxml import etree as LX

source = Path(r'C:\Users\anand\Desktop\serpent\test.txt')
target = Path(r'C:\Users\anand\Desktop\serpent\test2.txt')
sourcelang = 'fr'
targetlang = 'en'
outputfile = 'Aligner.tmx'

langattribute = LX.QName("http://www.w3.org/XML/1998/namespace", "lang")
original = LX.QName("o-tmf")

with open(source) as source_file, open(target) as target_file:
    source_tuv = source_file.read().splitlines()
    target_tuv = target_file.read().splitlines()
    
tmx = LX.Element('tmx', version='1.4')
header = LX.SubElement(tmx, 'header', creationtool='AnandTools', creationtoolversion='1.0', adminlang='en-US', segtype='sentence', srclang=sourcelang, datatype='plaintext')
header.set(original, 'txt')
body = LX.SubElement(tmx, 'body')

for(source_seg, target_seg) in zip(source_tuv, target_tuv):
        tu = LX.SubElement(body, 'tu')
        tuv1 = LX.SubElement(tu, 'tuv')
        tuv2 = LX.SubElement(tu, 'tuv')
        tuv1.set(langattribute, sourcelang)
        tuv2.set(langattribute, targetlang)
        seg1 = LX.SubElement(tuv1, 'seg')
        seg2 = LX.SubElement(tuv2, 'seg')
        seg1.text = source_seg.strip()
        seg2.text = target_seg.strip()
        
LX.indent(tmx)
a_xml = LX.tostring(tmx, encoding='utf-8', method='xml', xml_declaration=True, doctype='<!DOCTYPE tmx SYSTEM "tmx14.dtd">')

            
with open(outputfile, 'wb') as f:            
    f.write(a_xml)
Code avec moins de problèmes d'indentations : ```python from pathlib import Path from lxml import etree as LX source = Path(r'C:\Users\anand\Desktop\serpent\test.txt') target = Path(r'C:\Users\anand\Desktop\serpent\test2.txt') sourcelang = 'fr' targetlang = 'en' outputfile = 'Aligner.tmx' langattribute = LX.QName("http://www.w3.org/XML/1998/namespace", "lang") original = LX.QName("o-tmf") with open(source) as source_file, open(target) as target_file: source_tuv = source_file.read().splitlines() target_tuv = target_file.read().splitlines() tmx = LX.Element('tmx', version='1.4') header = LX.SubElement(tmx, 'header', creationtool='AnandTools', creationtoolversion='1.0', adminlang='en-US', segtype='sentence', srclang=sourcelang, datatype='plaintext') header.set(original, 'txt') body = LX.SubElement(tmx, 'body') for(source_seg, target_seg) in zip(source_tuv, target_tuv): tu = LX.SubElement(body, 'tu') tuv1 = LX.SubElement(tu, 'tuv') tuv2 = LX.SubElement(tu, 'tuv') tuv1.set(langattribute, sourcelang) tuv2.set(langattribute, targetlang) seg1 = LX.SubElement(tuv1, 'seg') seg2 = LX.SubElement(tuv2, 'seg') seg1.text = source_seg.strip() seg2.text = target_seg.strip() LX.indent(tmx) a_xml = LX.tostring(tmx, encoding='utf-8', method='xml', xml_declaration=True, doctype='<!DOCTYPE tmx SYSTEM "tmx14.dtd">') with open(outputfile, 'wb') as f: f.write(a_xml) ```
Collaborator

Code avec moins de problèmes d'indentations :

Pas seulement « moins de problèmes », mais bien « pas de problèmes ». Bravo ! Vous avez réglé tous les cas d'indentation suspecte.

L'ajout de variables pour les langues source et cible, et pour le nom du fichier de sortie, est aussi une excellente amélioration par rapport à la version précédente du code.

Il ne me reste que des petites suggestions du côté présentation/formatage du code. C'est une question de préférence personnelle, mais comme j'aime aérer le code, j'apporterais quelques changements mineurs pour faciliter la lecture et mettre en évidence les éléments de même nature.

Dans la section qui déclare les variables :

source = Path(r'C:\Users\anand\Desktop\serpent\test.txt')
target = Path(r'C:\Users\anand\Desktop\serpent\test2.txt')
outputfile = 'Aligner.tmx'

sourcelang = 'fr'
targetlang = 'en'
 
langattribute = LX.QName("http://www.w3.org/XML/1998/namespace", "lang")
original = LX.QName("o-tmf")

J'ai utilisé des lignes vides pour séparer le bloc de variables concernant les fichiers d'entrée et de sortie, le bloc avec les langues, et (comme vous l'aviez déjà fait), le bloc de variables représentant des attributs d'éléments XML.

Dans la boucle qui crée l'élément <tu> et les <tuv> et <seg> qui s'y trouve :

for(source_seg, target_seg) in zip(source_tuv, target_tuv):

        tu = LX.SubElement(body, 'tu')

        tuv1 = LX.SubElement(tu, 'tuv')
        tuv1.set(langattribute, sourcelang)
        seg1 = LX.SubElement(tuv1, 'seg')
        seg1.text = source_seg.strip()
                
        tuv2 = LX.SubElement(tu, 'tuv')
        tuv2.set(langattribute, targetlang)
        seg2 = LX.SubElement(tuv2, 'seg')
        seg2.text = target_seg.strip()

Encore quelques lignes vides supplémentaire pour démarquer l'élément <tu> et les éléments <tuv>. J'ai aussi changé l'ordre des lignes pour mettre tous les éléments d'un même <tuv> ensemble.

Pour moi, c'est plus fidèle à la progression que je visualise pour le code une fois qu'on entre dans la boucle :

  • créer l'élément <tu> ;
  • ajouter le premier élément <tuv> dans la langue source ;
  • insérer l'élément <seg> et son texte dans ce premier <tuv>;
  • ajouter le deuxième élément <tuv> dans la langue cible ;
  • insérer l'élément <seg> et son texte dans ce deuxième <tuv>.

Ça ne change en rien la fonctionnalité du code ou son résultat. Toutefois, ça le rend plus facile à lire, corriger, ou modifier pour quelqu'un qui veut s'en servir où y ajouter des fonctionnalités (c.-à-d. moi deux jours plus tard quand je me demande qu'est-ce que je cherchais à faire avec mon code !).

À méditer !

> Code avec moins de problèmes d'indentations : Pas seulement « moins de problèmes », mais bien « pas de problèmes ». Bravo ! Vous avez réglé tous les cas d'indentation suspecte. L'ajout de variables pour les langues source et cible, et pour le nom du fichier de sortie, est aussi une excellente amélioration par rapport à la version précédente du code. Il ne me reste que des petites suggestions du côté présentation/formatage du code. C'est une question de préférence personnelle, mais comme j'aime aérer le code, j'apporterais quelques changements mineurs pour faciliter la lecture et mettre en évidence les éléments de même nature. Dans la section qui déclare les variables : ```python source = Path(r'C:\Users\anand\Desktop\serpent\test.txt') target = Path(r'C:\Users\anand\Desktop\serpent\test2.txt') outputfile = 'Aligner.tmx' sourcelang = 'fr' targetlang = 'en' langattribute = LX.QName("http://www.w3.org/XML/1998/namespace", "lang") original = LX.QName("o-tmf") ``` J'ai utilisé des lignes vides pour séparer le bloc de variables concernant les fichiers d'entrée et de sortie, le bloc avec les langues, et (comme vous l'aviez déjà fait), le bloc de variables représentant des attributs d'éléments XML. Dans la boucle qui crée l'élément `<tu>` et les `<tuv>` et `<seg>` qui s'y trouve : ```python for(source_seg, target_seg) in zip(source_tuv, target_tuv): tu = LX.SubElement(body, 'tu') tuv1 = LX.SubElement(tu, 'tuv') tuv1.set(langattribute, sourcelang) seg1 = LX.SubElement(tuv1, 'seg') seg1.text = source_seg.strip() tuv2 = LX.SubElement(tu, 'tuv') tuv2.set(langattribute, targetlang) seg2 = LX.SubElement(tuv2, 'seg') seg2.text = target_seg.strip() ``` Encore quelques lignes vides supplémentaire pour démarquer l'élément `<tu>` et les éléments `<tuv>`. J'ai aussi changé l'ordre des lignes pour mettre tous les éléments d'un même `<tuv>` ensemble. Pour moi, c'est plus fidèle à la progression que je visualise pour le code une fois qu'on entre dans la boucle : - créer l'élément `<tu>` ; - ajouter le premier élément `<tuv>` dans la langue source ; - insérer l'élément `<seg>` et son texte dans ce premier `<tuv>`; - ajouter le deuxième élément `<tuv>` dans la langue cible ; - insérer l'élément `<seg>` et son texte dans ce deuxième `<tuv>`. Ça ne change en rien la fonctionnalité du code ou son résultat. Toutefois, ça le rend plus facile à lire, corriger, ou modifier pour quelqu'un qui veut s'en servir où y ajouter des fonctionnalités (c.-à-d. moi deux jours plus tard quand je me demande qu'est-ce que je cherchais à faire avec mon code !). À méditer !
Collaborator

Tel que promis, je vous présente le code complet de mon script.

En fait, je vous en présente trois variantes deux qui utilisent lxml et une qui utilise xml.etree.ElementTree. Vous les trouverez dans la section code du dépot.

  • textes_à_tmx_(lxml_objectify).py

    La variante principale (« pseudo-pédagogique »), à laquelle j'ai ajouté beaucoup de commentaires détaillés sur le code.

  • textes_à_tmx_(lxml_etree).py

    Variante qui utilise l'API principale du module lxml.

  • textes_à_tmx_(xml.etree.ElementTree).py

    La variante qui n'utilise que la bibliothèque Python standard.

J'ai aussi inclus le répertoire fichiers_texte avec les fichiers que j'ai utilisés pour vérifier les résultats du script. Vous pouvez donc l'essayer directement, ou remplacer mes fichiers par les vôtres.

Enfin, vous trouverez également des explications complémentaires sur le wiki.

Bonne lecture !

Tel que promis, je vous présente le code complet de mon script. En fait, je vous en présente trois variantes deux qui utilisent `lxml` et une qui utilise `xml.etree.ElementTree`. Vous les trouverez dans la [section code du dépot](https://forge.chapril.org/ciri/stage_2023/src/branch/kazephil/utilitaire_python). - `textes_à_tmx_(lxml_objectify).py` La variante principale (« pseudo-pédagogique »), à laquelle j'ai ajouté beaucoup de commentaires détaillés sur le code. - `textes_à_tmx_(lxml_etree).py` Variante qui utilise l'API principale du module `lxml`. - `textes_à_tmx_(xml.etree.ElementTree).py` La variante qui n'utilise que la bibliothèque Python standard. J'ai aussi inclus le répertoire `fichiers_texte` avec les fichiers que j'ai utilisés pour vérifier les résultats du script. Vous pouvez donc l'essayer directement, ou remplacer mes fichiers par les vôtres. Enfin, vous trouverez également des explications complémentaires [sur le wiki](https://forge.chapril.org/ciri/stage_2023/wiki/Exemple-de-script-pour-cr%C3%A9er-une-TMX). Bonne lecture !
Collaborator

Suite d’hier.

Je pense que j’ai trop installé de versions différentes de python sur ma machine et c’est pour ça que lxml n’arrive pas à s’installer.

J’ai tout repris en n’utilisant pas le gestionnaire de paquets brew mais macport à la place et j’arrive à faire tout fonctionner, mais c’est moche parce que la version de tkinter de macport n’utilise pas l’interface graphique de macOS par défaut, mais à la place un équivalent de l’interface graphique qu’on trouve sur Linux, par l’intermédiaire de l’application Xquartz…

Comme bilan, mais également à l’attention de @kazephil qui nous regarde, on a fait ça hier :

À partir de ça on a fait un prototype de notre interface en utilisant juste des ‘label’ et des ‘button’.

from tkinter import *
from tkinter import ttk

root = Tk()
frm = ttk.Frame(root, padding=10)
frm.grid()

ttk.Label(frm, text="  Fichier source : ").grid(column=0, row=0, pady=10)
ttk.Button(frm, text="Parcourir", command=root.destroy).grid(column=1, row=0)
ttk.Label(frm, text="  Langue source : ").grid(column=0, row=1)
sourcelangEntry=ttk.Entry(frm, text="fr").grid(column=1, row=1)
sourcelang=StringVar()
sourcelang.set="fr"
sourcelangEntry[0] = sourcelang


ttk.Label(frm, text="  Fichier cible : ").grid(column=0, row=2, pady=10)
ttk.Button(frm, text="Parcourir", command=root.destroy).grid(column=1, row=2)
ttk.Label(frm, text="  Langue cible : ").grid(column=0, row=3)
ttk.Entry(frm, text="en").grid(column=1, row=3)
targetlang=StringVar()
targetlang.set="en"


ttk.Label(frm, text="  Fichier TMX : ").grid(column=0, row=4, pady=10)
ttk.Button(frm, text="Parcourir", command=root.destroy).grid(column=1, row=4)


ttk.Button(frm, text="Annuler", command=root.destroy).grid(column=0, row=5, pady=10)
ttk.Button(frm, text="Aligner", command=root.destroy).grid(column=1, row=5)


root.mainloop()
  • ensuite, on a tenté d’aller chercher nos variables

Pour ça, on a utilisé le code correspondant à la section ‘Association des variables de l’objet graphique’

On n’a pas réussi à y intégrer notre prototype (les explications sur le ‘sous-classage’ nous sont passées très haut au-dessus de la tête) et on a trouvé un tutoriel qui correspondait plus à notre prototype

https://www.geeksforgeeks.org/python-tkinter-entry-widget/

On a encore des bricoles à gérer :

TypeError: can only concatenate str (not "StringVar") to str

mais on avance.

Voici le code aujourd’hui :

import lxml as LX
import tkinter as tk
from pathlib import Path

# définition des chemins
source = Path(r'C:\Users\anand\Desktop\serpent\test.txt')
target = Path(r'C:\Users\anand\Desktop\serpent\test2.txt')
outputfile = 'Aligner.tmx'

# définition des codes langue

root=tk.Tk()

## setting the windows size
## root.geometry("600x400")

## declaring string variable
## for storing langsource and langcible
langsource_var=tk.StringVar()
langcible_var=tk.StringVar()
langsource_var.set("fr")
langcible_var.set("en")
		
 
## creating a label for
## langsource using widget Label
langsource_label = tk.Label(root, text = 'Langue source : ', font=('calibre',10, 'bold'))

## creating a entry for input
## langsource using widget Entry
langsource_entry = tk.Entry(root,textvariable = langsource_var, font=('calibre',10,'normal'))

## creating a label for langcible
langcible_label = tk.Label(root, text = 'Langue cible : ', font = ('calibre',10,'bold'))

## creating a entry for langcible
langcible_entry=tk.Entry(root, textvariable = langcible_var, font = ('calibre',10,'normal'))

## creating a button using the widget
## Button that will call the submit function
sub_btn=tk.Button(root,text = 'Submit', command = root.destroy)

## placing the label and entry in
## the required position using grid
## method
langsource_label.grid(row=0,column=0)
langsource_entry.grid(row=0,column=1)
langcible_label.grid(row=1,column=0)
langcible_entry.grid(row=1,column=1)
sub_btn.grid(row=2,column=1)

## performing an infinite loop
## for the window to display
root.mainloop()

print("Langue source : " + langsource_var)
print("Langue cible : " + langcible_var)


# création de la TMX
langattribute = LX.QName("http://www.w3.org/XML/1998/namespace", "lang")
original = LX.QName("o-tmf")

with open(source) as source_file, open(target) as target_file:
    source_tuv = source_file.read().splitlines()
    target_tuv = target_file.read().splitlines()
    
tmx = LX.Element('tmx', version='1.4')
header = LX.SubElement(tmx, 'header', creationtool='AnandTools', creationtoolversion='1.0', adminlang='en-US', segtype='sentence', srclang=sourcelang, datatype='plaintext')
header.set(original, 'txt')
body = LX.SubElement(tmx, 'body')

for(source_seg, target_seg) in zip(source_tuv, target_tuv):
        tu = LX.SubElement(body, 'tu')
        tuv1 = LX.SubElement(tu, 'tuv')
        tuv2 = LX.SubElement(tu, 'tuv')
        tuv1.set(langattribute, langsource_var)
        tuv2.set(langattribute, langcible_var)
        seg1 = LX.SubElement(tuv1, 'seg')
        seg2 = LX.SubElement(tuv2, 'seg')
        seg1.text = source_seg.strip()
        seg2.text = target_seg.strip()
        
LX.indent(tmx)
a_xml = LX.tostring(tmx, encoding='utf-8', method='xml', xml_declaration=True, doctype='<!DOCTYPE tmx SYSTEM "tmx14.dtd">')

            
with open(outputfile, 'wb') as f:            
    f.write(a_xml)

Tout ça, c’est beaucoup de copier/coller et quand ça marchera il faudra penser à
repasser ligne par ligne pour mettre des explications et être capable de comprendre ce que l’on a fait et à quoi on a abouti.

Au final, j’aimerais bien qu’on aboutisse à un document qui ressemble à notre transformation TMX/TBX (https://mac4translators.blogspot.com/2023/04/convertir-un-fichier-tmx-en-tbx-avec.html), avec le nom de tout le monde, comme aboutissement de ce stage, même si la finalisation du code et la publication auront lieu bien après les soutenances.

Suite d’hier. Je pense que j’ai trop installé de versions différentes de python sur ma machine et c’est pour ça que lxml n’arrive pas à s’installer. J’ai tout repris en n’utilisant pas le gestionnaire de paquets `brew` mais `macport` à la place et j’arrive à faire tout fonctionner, mais c’est moche parce que la version de tkinter de macport n’utilise pas l’interface graphique de macOS par défaut, mais à la place un équivalent de l’interface graphique qu’on trouve sur Linux, par l’intermédiaire de l’application Xquartz… Comme bilan, mais également à l’attention de @kazephil qui nous regarde, on a fait ça hier : - on a tenté d’utiliser le tutoriel tkinter du site officiel de documentation Python https://docs.python.org/fr/3/library/tkinter.html?highlight=tkinter#module-tkinter À partir de ça on a fait un prototype de notre interface en utilisant juste des ‘label’ et des ‘button’. ```Python from tkinter import * from tkinter import ttk root = Tk() frm = ttk.Frame(root, padding=10) frm.grid() ttk.Label(frm, text=" Fichier source : ").grid(column=0, row=0, pady=10) ttk.Button(frm, text="Parcourir", command=root.destroy).grid(column=1, row=0) ttk.Label(frm, text=" Langue source : ").grid(column=0, row=1) sourcelangEntry=ttk.Entry(frm, text="fr").grid(column=1, row=1) sourcelang=StringVar() sourcelang.set="fr" sourcelangEntry[0] = sourcelang ttk.Label(frm, text=" Fichier cible : ").grid(column=0, row=2, pady=10) ttk.Button(frm, text="Parcourir", command=root.destroy).grid(column=1, row=2) ttk.Label(frm, text=" Langue cible : ").grid(column=0, row=3) ttk.Entry(frm, text="en").grid(column=1, row=3) targetlang=StringVar() targetlang.set="en" ttk.Label(frm, text=" Fichier TMX : ").grid(column=0, row=4, pady=10) ttk.Button(frm, text="Parcourir", command=root.destroy).grid(column=1, row=4) ttk.Button(frm, text="Annuler", command=root.destroy).grid(column=0, row=5, pady=10) ttk.Button(frm, text="Aligner", command=root.destroy).grid(column=1, row=5) root.mainloop() ``` - ensuite, on a tenté d’aller chercher nos variables Pour ça, on a utilisé le code correspondant à la section ‘Association des variables de l’objet graphique’ On n’a pas réussi à y intégrer notre prototype (les explications sur le ‘sous-classage’ nous sont passées très haut au-dessus de la tête) et on a trouvé un tutoriel qui correspondait plus à notre prototype https://www.geeksforgeeks.org/python-tkinter-entry-widget/ On a encore des bricoles à gérer : ```Python TypeError: can only concatenate str (not "StringVar") to str ``` mais on avance. Voici le code aujourd’hui : ```Python import lxml as LX import tkinter as tk from pathlib import Path # définition des chemins source = Path(r'C:\Users\anand\Desktop\serpent\test.txt') target = Path(r'C:\Users\anand\Desktop\serpent\test2.txt') outputfile = 'Aligner.tmx' # définition des codes langue root=tk.Tk() ## setting the windows size ## root.geometry("600x400") ## declaring string variable ## for storing langsource and langcible langsource_var=tk.StringVar() langcible_var=tk.StringVar() langsource_var.set("fr") langcible_var.set("en") ## creating a label for ## langsource using widget Label langsource_label = tk.Label(root, text = 'Langue source : ', font=('calibre',10, 'bold')) ## creating a entry for input ## langsource using widget Entry langsource_entry = tk.Entry(root,textvariable = langsource_var, font=('calibre',10,'normal')) ## creating a label for langcible langcible_label = tk.Label(root, text = 'Langue cible : ', font = ('calibre',10,'bold')) ## creating a entry for langcible langcible_entry=tk.Entry(root, textvariable = langcible_var, font = ('calibre',10,'normal')) ## creating a button using the widget ## Button that will call the submit function sub_btn=tk.Button(root,text = 'Submit', command = root.destroy) ## placing the label and entry in ## the required position using grid ## method langsource_label.grid(row=0,column=0) langsource_entry.grid(row=0,column=1) langcible_label.grid(row=1,column=0) langcible_entry.grid(row=1,column=1) sub_btn.grid(row=2,column=1) ## performing an infinite loop ## for the window to display root.mainloop() print("Langue source : " + langsource_var) print("Langue cible : " + langcible_var) # création de la TMX langattribute = LX.QName("http://www.w3.org/XML/1998/namespace", "lang") original = LX.QName("o-tmf") with open(source) as source_file, open(target) as target_file: source_tuv = source_file.read().splitlines() target_tuv = target_file.read().splitlines() tmx = LX.Element('tmx', version='1.4') header = LX.SubElement(tmx, 'header', creationtool='AnandTools', creationtoolversion='1.0', adminlang='en-US', segtype='sentence', srclang=sourcelang, datatype='plaintext') header.set(original, 'txt') body = LX.SubElement(tmx, 'body') for(source_seg, target_seg) in zip(source_tuv, target_tuv): tu = LX.SubElement(body, 'tu') tuv1 = LX.SubElement(tu, 'tuv') tuv2 = LX.SubElement(tu, 'tuv') tuv1.set(langattribute, langsource_var) tuv2.set(langattribute, langcible_var) seg1 = LX.SubElement(tuv1, 'seg') seg2 = LX.SubElement(tuv2, 'seg') seg1.text = source_seg.strip() seg2.text = target_seg.strip() LX.indent(tmx) a_xml = LX.tostring(tmx, encoding='utf-8', method='xml', xml_declaration=True, doctype='<!DOCTYPE tmx SYSTEM "tmx14.dtd">') with open(outputfile, 'wb') as f: f.write(a_xml) ``` Tout ça, c’est beaucoup de copier/coller et quand ça marchera il faudra penser à repasser ligne par ligne pour mettre des explications et être capable de comprendre ce que l’on a fait et à quoi on a abouti. Au final, j’aimerais bien qu’on aboutisse à un document qui ressemble à notre transformation TMX/TBX (https://mac4translators.blogspot.com/2023/04/convertir-un-fichier-tmx-en-tbx-avec.html), avec le nom de tout le monde, comme aboutissement de ce stage, même si la finalisation du code et la publication auront lieu bien après les soutenances.
Collaborator

Suite d’hier.

Je pense que j’ai trop installé de versions différentes de python sur ma machine et c’est pour ça que lxml n’arrive pas à s’installer.

Tu peux essayer de créer un environnement virtuel avec la version de Python que tu veux utiliser pour l'utilitaire.

Autres articles utiles sur les environnements virtuels :

En principe, de là tout s'installe avec pip, plutôt qu'avec le gestionnaire de programme.

Installer tkinter dans l'environnement virtuel réglerait peut-être aussi le problème de l'utilisation de l'interface graphique macOS.

Comme bilan, mais également à l’attention de @kazephil qui nous regarde, on a fait ça hier :

Merci ! Je vais regarder ça avec intérêt.

  • on a tenté d’utiliser le tutoriel tkinter du site officiel de documentation Python

Autre tutoriel qui pourrait être intéressant :

Il porte sur Tk en général, avec des exemples non seulement en Python, mais aussi dans d'autres langages.

Et quelques autres choix d'intérêt spécifiquement orientés Python :

À partir de ça on a fait un prototype de notre interface en utilisant juste des ‘label’ et des ‘button’.

Ce code fonctionne tel quel de ton côté ?
Ici, il plante avec un erreur TypeError: 'NoneType' object does not support item assignment à la ligne :

sourcelangEntry[0] = sourcelang
  • ensuite, on a tenté d’aller chercher nos variables

Pour ça, on a utilisé le code correspondant à la section ‘Association des variables de l’objet graphique’

On n’a pas réussi à y intégrer notre prototype (les explications sur le ‘sous-classage’ nous sont passées très haut au-dessus de la tête) et on a trouvé un tutoriel qui correspondait plus à notre prototype

L'explication n'est effectivement pas très claire, et je pense qu'elle t'a induit en erreur.

https://www.geeksforgeeks.org/python-tkinter-entry-widget/

On a encore des bricoles à gérer :

TypeError: can only concatenate str (not "StringVar") to str

Question : Pourquoi utilises-tu la fonction print() ?
Si tu veux imprimer imprimer à la console, il faut récupérer (get) la valeur de la variable de type StringVar.

mais on avance.

C'est ça qui compte !

Voici le code aujourd’hui :

import lxml as LX

Attention, ce n'est pas lxml que l'on importe, mais plutôt le(s) module(s) désiré(s) offert par cette bibliothèque.

Retourne voir le code d'Anand quelques commentaires plus haut.

Mais pour l'interface graphique, ce code me présente un petit dialogue avec « fr » comme langue source et « en » comme langue cible, et un bouton « Submit ».

Tout ça, c’est beaucoup de copier/coller et quand ça marchera il faudra penser à
repasser ligne par ligne pour mettre des explications et être capable de comprendre ce que l’on a fait et à quoi on a abouti.

J'attends patiemment la suite !

> Suite d’hier. > > Je pense que j’ai trop installé de versions différentes de python sur ma machine et c’est pour ça que lxml n’arrive pas à s’installer. Tu peux essayer de créer un [environnement virtuel](https://docs.python.org/fr/3/library/venv.html) avec la version de Python que tu veux utiliser pour l'utilitaire. Autres articles utiles sur les environnements virtuels : - https://openclassrooms.com/fr/courses/6951236-mettez-en-place-votre-environnement-python/7014018-creez-votre-premier-environnement-virtuel - https://realpython.com/python-virtual-environments-a-primer/ En principe, de là tout s'installe avec `pip`, plutôt qu'avec le gestionnaire de programme. Installer tkinter dans l'environnement virtuel réglerait peut-être aussi le problème de l'utilisation de l'interface graphique macOS. > Comme bilan, mais également à l’attention de @kazephil qui nous regarde, on a fait ça hier : Merci ! Je vais regarder ça avec intérêt. > - on a tenté d’utiliser le tutoriel tkinter du site officiel de documentation Python Autre tutoriel qui pourrait être intéressant : - https://tkdocs.com/tutorial/ Il porte sur Tk en général, avec des exemples non seulement en Python, mais aussi dans d'autres langages. Et quelques autres choix d'intérêt spécifiquement orientés Python : - https://www.pythonguis.com/tkinter/ (mis à jour récemment) - https://realpython.com/python-gui-tkinter/ (Real Python a généralement de bons articles) - https://vincent.developpez.com/cours-tutoriels/python/tkinter/apprendre-creer-interface-graphique-tkinter-python-3/ (un peu daté, mais en français) - https://github.com/Dvlv/Tkinter-By-Example (aussi un peu daté, mais les exemples concrets peuvent être utiles) > À partir de ça on a fait un prototype de notre interface en utilisant juste des ‘label’ et des ‘button’. Ce code fonctionne tel quel de ton côté ? Ici, il plante avec un erreur `TypeError: 'NoneType' object does not support item assignment` à la ligne : ```Python sourcelangEntry[0] = sourcelang ``` > - ensuite, on a tenté d’aller chercher nos variables > > Pour ça, on a utilisé le code correspondant à la section ‘Association des variables de l’objet graphique’ > > On n’a pas réussi à y intégrer notre prototype (les explications sur le ‘sous-classage’ nous sont passées très haut au-dessus de la tête) et on a trouvé un tutoriel qui correspondait plus à notre prototype L'explication n'est effectivement pas très claire, et je pense qu'elle t'a induit en erreur. > https://www.geeksforgeeks.org/python-tkinter-entry-widget/ > > On a encore des bricoles à gérer : > > ```Python > TypeError: can only concatenate str (not "StringVar") to str > ``` Question : Pourquoi utilises-tu la fonction `print()` ? Si tu veux imprimer imprimer à la console, il faut récupérer (`get`) la valeur de la variable de type `StringVar`. > mais on avance. C'est ça qui compte ! > Voici le code aujourd’hui : > > ```Python > import lxml as LX > ``` Attention, ce n'est pas `lxml` que l'on importe, mais plutôt le(s) module(s) désiré(s) offert par cette bibliothèque. Retourne voir le code d'Anand quelques commentaires plus haut. Mais pour l'interface graphique, ce code me présente un petit dialogue avec « fr » comme langue source et « en » comme langue cible, et un bouton « Submit ». > Tout ça, c’est beaucoup de copier/coller et quand ça marchera il faudra penser à > repasser ligne par ligne pour mettre des explications et être capable de comprendre ce que l’on a fait et à quoi on a abouti. J'attends patiemment la suite !
Author
Owner

J’ai tenté de reprendre le code du début et d’y apporter des modifications pour résoudre les problèmes que nous avions rencontrés auparavant. En cours de route, j'ai découvert quelques fonctions et méthodes que j'ai voulu tester, et comme toujours il y a beaucoup de copier/coller. Au final, je pense avoir plus appris grâce aux messages d'erreur qu'aux tutoriels…

Voici ce que ça donne pour l’instant :

from lxml import etree as LX
import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox

# Definition des chemins
outputfile = 'Aligner.tmx'

# Aligner les fichiers source/cible 
def align_files():
    source_file_path = source_entry.get()
    target_file_path = target_entry.get()
    source_lang_var = source_lang_entry.get()
    target_lang_var = target_lang_entry.get()

    # Création de la TMX
    langattribute = LX.QName("http://www.w3.org/XML/1998/namespace", "lang")
    original = LX.QName("o-tmf")

    with open(source_file_path) as source_file, open(target_file_path) as target_file:
        source_tuv = source_file.read().splitlines()
        target_tuv = target_file.read().splitlines()

    tmx = LX.Element('tmx', version='1.4')
    header = LX.SubElement(tmx, 'header', creationtool='AnandTools', creationtoolversion='1.0', adminlang='en-US', segtype='sentence', srclang=source_lang_var, datatype='plaintext')
    header.set(original, 'txt')
    body = LX.SubElement(tmx, 'body')

    aligned_text = ""

    for (source_seg, target_seg) in zip(source_tuv, target_tuv):
        aligned_text += f"{source_seg.strip()}\n ->\n{target_seg.strip()}\n\n"

        tu = LX.SubElement(body, 'tu')
        tuv1 = LX.SubElement(tu, 'tuv')
        tuv2 = LX.SubElement(tu, 'tuv')
        tuv1.set(langattribute, source_lang_var)
        tuv2.set(langattribute, target_lang_var)
        seg1 = LX.SubElement(tuv1, 'seg')
        seg2 = LX.SubElement(tuv2, 'seg')
        seg1.text = source_seg.strip()
        seg2.text = target_seg.strip()

    LX.indent(tmx)
    a_xml = LX.tostring(tmx, encoding='utf-8', method='xml', xml_declaration=True, doctype='<!DOCTYPE tmx SYSTEM "tmx14.dtd">')

    with open(outputfile, 'wb') as f:
        f.write(a_xml)

    # Paramètres d'affichage du texte aligné
    text_output.config(state=tk.NORMAL)
    text_output.delete(1.0, tk.END)
    text_output.insert(tk.END, aligned_text)
    text_output.config(state=tk.DISABLED)

    # Afficher un message une fois l'alignement terminé
    messagebox.showinfo(title=None, message="Alignement Terminé")

# Paramètres de la fenêtre
root = tk.Tk()
root.title("Aligneur de texte")

frame = tk.Frame(root)
frame.pack(padx=200, pady=100)

# FICHIER SOURCE
# Nom
fichier_source = tk.Label(frame, text="Fichier source :")
fichier_source.grid(row=0, column=0, padx=10, pady=5)

# Champ de saisie
source_entry = tk.Entry(frame)
source_entry.grid(row=0, column=1, padx=10, pady=5)

# Bouton
source_bouton = tk.Button(frame, text="Parcourir", command=lambda: source_entry.insert(tk.END, filedialog.askopenfilename()))
source_bouton.grid(row=0, column=2, padx=10, pady=5)

# LANGUE SOURCE
# Nom
source_lang_label = tk.Label(frame, text="Langue source :")
source_lang_label.grid(row=1, column=0, padx=10, pady=5)

# Champ de saisie
source_lang_entry = tk.Entry(frame)
source_lang_entry.grid(row=1, column=1, padx=10, pady=5)

# FICHIER CIBLE
# Nom
target_file = tk.Label(frame, text="Fichier cible :")
target_file.grid(row=2, column=0, padx=10, pady=5)

# Champ de saisie
target_entry = tk.Entry(frame)
target_entry.grid(row=2, column=1, padx=10, pady=5)

# Bouton
target_bouton = tk.Button(frame, text="Parcourir", command=lambda: target_entry.insert(tk.END, filedialog.askopenfilename()))
target_bouton.grid(row=2, column=2, padx=10, pady=5)

# LANGUE CIBLE
# Nom
target_lang_label = tk.Label(frame, text="Langue cible :")
target_lang_label.grid(row=3, column=0, padx=10, pady=5)

# Champ de saisie
target_lang_entry = tk.Entry(frame)
target_lang_entry.grid(row=3, column=1, padx=10, pady=5)

# Bouton Aligner
aligner_bouton = tk.Button(frame, text="Aligner", command=lambda: [align_files()])
aligner_bouton.grid(row=4, column=0, columnspan=3, padx=10, pady=5)

# Texte aligné
text_output = tk.Text(frame, wrap="word", width=100, height=80, state=tk.DISABLED)
text_output.grid(row=5, column=0, columnspan=3, padx=10, pady=5)

root.mainloop()

(Ce n'est pas très utile, mais j'ai ajouté une petite fenêtre qui indique que l'alignement est terminé.)
https://docs.python.org/3/library/tkinter.messagebox.html

Pour le reste, j'ai repris ce que nous avons vu ensemble, avec quelques informations et explications trouvées ici et là (merci internet). Le code fonctionne, mais il a bien sûr besoin d'être amélioré.

J’ai tenté de reprendre le code du début et d’y apporter des modifications pour résoudre les problèmes que nous avions rencontrés auparavant. En cours de route, j'ai découvert quelques fonctions et méthodes que j'ai voulu tester, et comme toujours il y a beaucoup de copier/coller. Au final, je pense avoir plus appris grâce aux messages d'erreur qu'aux tutoriels… Voici ce que ça donne pour l’instant : ```python from lxml import etree as LX import tkinter as tk from tkinter import filedialog from tkinter import messagebox # Definition des chemins outputfile = 'Aligner.tmx' # Aligner les fichiers source/cible def align_files(): source_file_path = source_entry.get() target_file_path = target_entry.get() source_lang_var = source_lang_entry.get() target_lang_var = target_lang_entry.get() # Création de la TMX langattribute = LX.QName("http://www.w3.org/XML/1998/namespace", "lang") original = LX.QName("o-tmf") with open(source_file_path) as source_file, open(target_file_path) as target_file: source_tuv = source_file.read().splitlines() target_tuv = target_file.read().splitlines() tmx = LX.Element('tmx', version='1.4') header = LX.SubElement(tmx, 'header', creationtool='AnandTools', creationtoolversion='1.0', adminlang='en-US', segtype='sentence', srclang=source_lang_var, datatype='plaintext') header.set(original, 'txt') body = LX.SubElement(tmx, 'body') aligned_text = "" for (source_seg, target_seg) in zip(source_tuv, target_tuv): aligned_text += f"{source_seg.strip()}\n ->\n{target_seg.strip()}\n\n" tu = LX.SubElement(body, 'tu') tuv1 = LX.SubElement(tu, 'tuv') tuv2 = LX.SubElement(tu, 'tuv') tuv1.set(langattribute, source_lang_var) tuv2.set(langattribute, target_lang_var) seg1 = LX.SubElement(tuv1, 'seg') seg2 = LX.SubElement(tuv2, 'seg') seg1.text = source_seg.strip() seg2.text = target_seg.strip() LX.indent(tmx) a_xml = LX.tostring(tmx, encoding='utf-8', method='xml', xml_declaration=True, doctype='<!DOCTYPE tmx SYSTEM "tmx14.dtd">') with open(outputfile, 'wb') as f: f.write(a_xml) # Paramètres d'affichage du texte aligné text_output.config(state=tk.NORMAL) text_output.delete(1.0, tk.END) text_output.insert(tk.END, aligned_text) text_output.config(state=tk.DISABLED) # Afficher un message une fois l'alignement terminé messagebox.showinfo(title=None, message="Alignement Terminé") # Paramètres de la fenêtre root = tk.Tk() root.title("Aligneur de texte") frame = tk.Frame(root) frame.pack(padx=200, pady=100) # FICHIER SOURCE # Nom fichier_source = tk.Label(frame, text="Fichier source :") fichier_source.grid(row=0, column=0, padx=10, pady=5) # Champ de saisie source_entry = tk.Entry(frame) source_entry.grid(row=0, column=1, padx=10, pady=5) # Bouton source_bouton = tk.Button(frame, text="Parcourir", command=lambda: source_entry.insert(tk.END, filedialog.askopenfilename())) source_bouton.grid(row=0, column=2, padx=10, pady=5) # LANGUE SOURCE # Nom source_lang_label = tk.Label(frame, text="Langue source :") source_lang_label.grid(row=1, column=0, padx=10, pady=5) # Champ de saisie source_lang_entry = tk.Entry(frame) source_lang_entry.grid(row=1, column=1, padx=10, pady=5) # FICHIER CIBLE # Nom target_file = tk.Label(frame, text="Fichier cible :") target_file.grid(row=2, column=0, padx=10, pady=5) # Champ de saisie target_entry = tk.Entry(frame) target_entry.grid(row=2, column=1, padx=10, pady=5) # Bouton target_bouton = tk.Button(frame, text="Parcourir", command=lambda: target_entry.insert(tk.END, filedialog.askopenfilename())) target_bouton.grid(row=2, column=2, padx=10, pady=5) # LANGUE CIBLE # Nom target_lang_label = tk.Label(frame, text="Langue cible :") target_lang_label.grid(row=3, column=0, padx=10, pady=5) # Champ de saisie target_lang_entry = tk.Entry(frame) target_lang_entry.grid(row=3, column=1, padx=10, pady=5) # Bouton Aligner aligner_bouton = tk.Button(frame, text="Aligner", command=lambda: [align_files()]) aligner_bouton.grid(row=4, column=0, columnspan=3, padx=10, pady=5) # Texte aligné text_output = tk.Text(frame, wrap="word", width=100, height=80, state=tk.DISABLED) text_output.grid(row=5, column=0, columnspan=3, padx=10, pady=5) root.mainloop() ``` * J'ai retiré `from pathlib import Path` car je voulais que le bouton `Parcourir` nous permette de réellement parcourir nos fichiers pour en sélectionner un. Il a donc été remplacé par `from tkinter import filedialog` https://www.youtube.com/watch?v=Aim_7fC-inw&feature=youtu.be * J'ai ajouté la fonction `align_files()` avec la méthode `.get()` qui utilise les chemins de fichiers et les informations entrées dans l'interface pour aligner les fichiers. https://www.w3schools.com/python/ref_dictionary_get.asp * Ensuite, pour créer une boucle qui permet d'afficher les deux textes segment par segment, j’ai utilisé `aligned_text +=` pour ajouter les deux valeurs définies dans le f-String `f"{source_seg.strip()}\\n ->\\n{target_seg.strip()}\\n\\n"`, ce qui nous permettra d'afficher le contenu des deux fichiers simultanément. https://www.w3schools.com/python/python_operators.asp https://realpython.com/python-f-strings/ * Enfin, pour afficher le texte aligné dans la même fenêtre, j'ai utilisé le "Text Widget" de Tkinter. https://www.geeksforgeeks.org/python-tkinter-text-widget/ (Ce n'est pas très utile, mais j'ai ajouté une petite fenêtre qui indique que l'alignement est terminé.) https://docs.python.org/3/library/tkinter.messagebox.html Pour le reste, j'ai repris ce que nous avons vu ensemble, avec quelques informations et explications trouvées ici et là (merci internet). Le code fonctionne, mais il a bien sûr besoin d'être amélioré.
Collaborator

Merci pour le code et pour les commentaires et vidéos.

Je viens de tester. C'est parfait.

La grosse fenêtre pourrait peut-être être remplacée par un affichage en 2 colonnes qui affiche les contenus de chaque fichier.

Et ça pourrait servir de point de départ (soyons dingues !) à une fonction de correction de l'alignement au cas où les deux fichiers ne sont pas pile-poil alignés...

Merci pour le code et pour les commentaires et vidéos. Je viens de tester. C'est parfait. La grosse fenêtre pourrait peut-être être remplacée par un affichage en 2 colonnes qui affiche les contenus de chaque fichier. Et ça pourrait servir de point de départ (soyons dingues !) à une fonction de correction de l'alignement au cas où les deux fichiers ne sont pas pile-poil alignés...
Sign in to join this conversation.
No Milestone
No project
4 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

2023-05-08

Dependencies

No dependencies set.

Reference: ciri/stage_2023#50
No description provided.