GUI tkinter à Convertir un fichier Largeur fixe vers un fichier Délimité
-
27-10-2019 - |
Question
Je suis en train d'écrire un code de conversion pour notre département de données pour convertir des fichiers en fichiers largeur fixe delmited. Normalement, nous utilisons importer le fichier dans Excel, utilisez l'assistant d'importation de texte pour définir les longueurs de terrain, et puis juste enregistrer comme un fichier CSV. Cependant, nous avons couru dans la limite où nous avons commencé à obtenir des fichiers qui sont des millions d'enregistrements long, et donc cant être importées dans Excel. Les fichiers ne sont pas toujours des espaces entre les champs, espicially donc entre les champs de valeur comme les numéros de téléphone ou des codes postaux. Les en-têtes sont souvent complètement remplis sans espaces.
Un échantillon d'un fichier largeur fixe typique que nous avons affaire à:
SequenSack and PaFull Name****************************]JOB TITLE****************]HOSP NAME******************************]Delivery Address***********************]Alternate 1 Address********************]Calculated Text**********************************]POSTNET Bar
000001T1 P1 Sample A Sample 123 Any Street Anytown 12345-6789 12345678900
000002T1 P1 Sample A Sample Director of Medicine 123 Any Street Po Box 1234 Anytown 12345-6789 12345678900
Les besoins du programme de fichier pause dans les champs délimités suivants:
Sequen
Sac et Pa
Nom complet
Intitulé du poste
Nom
Hosp
Adresse de livraison
Autre adresse 1
Calculé Texte
POSTNET Bar
Chaque fichier comme une largeur légèrement différente de chaque champ en fonction du reste de la tâche. Qu'est-ce que je cherche est une interface graphique orientée delimiter un peu comme l'assistant d'importation Excel pour les fichiers à largeur fixe. Je vous écris cet outil en Python comme une partie d'un plus grand outil qui fait beaucoup d'autres opérations de fichiers tels que la rupture des fichiers en plusieurs haut, en inversant un fichier, conversion de délimité à largeur fixe et la vérification du chiffre de contrôle. J'utilise Tkinter pour le reste des outils et il serait idéal si l'utilisation de la solution ainsi.
Toute aide appréciée
La solution
Si je comprends bien le problème (et il y a une bonne chance que je ne veux pas ...), la solution la plus simple serait d'utiliser un widget texte.
Faire la première ligne soit une série d'espaces de la même longueur que la rangée. Utilisez deux balises alternatives (par exemple: « même » et « impair ») pour donner chaque caractère une autre couleur afin qu'ils se distinguent les uns des autres. La deuxième ligne serait l'en-tête, et toutes les lignes restantes serait quelques lignes de données échantillon.
Ensuite, mettre en place des liaisons sur la première ligne pour convertir un espace dans un « x » lorsque l'utilisateur clique sur un personnage. S'ils cliquent sur un « x », reconvertir en un espace. Ils peuvent ensuite aller et cliquez sur le caractère qui est le début de chaque colonne. Lorsque l'utilisateur est fait, vous pouvez obtenir la première ligne du widget texte et il aura un « x » pour chaque colonne. Ensuite, vous avez juste besoin d'une petite fonction qui traduit que dans le format que vous avez besoin.
Il semble à peu près comme ça (bien évidemment les couleurs seraient différentes de ce qui apparaît sur ce site)
x x x ...
SequenSack and PaFull Name****************************]JOB...
000001T1 P1 Sample A Sample ...
Voici un hack pour illustrer l'idée générale. Il est un peu bâclée, mais je pense qu'il illustre la technique. Lorsque vous exécutez, cliquez sur une zone dans la première rangée de définir ou d'effacer un marqueur. Cela entraînera l'en-tête à mettre en valeur dans des couleurs alternatives pour chaque marqueur.
import sys
import Tkinter as tk
import tkFont
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
header = "SequenSack and PaFull Name****************************]JOB TITLE****************]HOSP NAME******************************]Delivery Address***********************]Alternate 1 Address********************]Calculated Text**********************************]POSTNET Bar"
sample = "000001T1 P1 Sample A Sample 123 Any Street Anytown 12345-6789 12345678900"
widget = DelimiterWidget(self, header, sample)
hsb = tk.Scrollbar(orient="horizontal", command=widget.xview)
widget.configure(xscrollcommand=hsb.set)
hsb.pack(side="bottom", fill="x")
widget.pack(side="top", fill="x")
class DelimiterWidget(tk.Text):
def __init__(self, parent, header, samplerow):
fixedFont = tkFont.nametofont("TkFixedFont")
tk.Text.__init__(self, parent, wrap="none", height=3, font=fixedFont)
self.configure(cursor="left_ptr")
self.tag_configure("header", background="gray")
self.tag_configure("even", background="#ffffff")
self.tag_configure("header_even", background="bisque")
self.tag_configure("header_odd", background="lightblue")
self.tag_configure("odd", background="#eeeeee")
markers = " "*len(header)
for i in range(len(header)):
tag = "even" if i%2==0 else "odd"
self.insert("end", " ", (tag,))
self.insert("end", "\n")
self.insert("end", header+"\n", "header")
self.insert("end", samplerow, "sample")
self.configure(state="disabled")
self.bind("<1>", self.on_click)
self.bind("<Double-1>", self.on_click)
self.bind("<Triple-1>", self.on_click)
def on_click(self, event):
'''Handle a click on a marker'''
index = self.index("@%s,%s" % (event.x, event.y))
current = self.get(index)
self.configure(state="normal")
self.delete(index)
(line, column) = index.split(".")
tag = "even" if int(column)%2 == 0 else "odd"
char = " " if current == "x" else "x"
self.insert(index, char, tag)
self.configure(state="disabled")
self.highlight_header()
return "break"
def highlight_header(self):
'''Highlight the header based on marker positions'''
self.tag_remove("header_even", 1.0, "end")
self.tag_remove("header_odd", 1.0, "end")
markers = self.get(1.0, "1.0 lineend")
i = 0
start = "2.0"
tag = "header_even"
while True:
try:
i = markers.index("x", i+1)
end = "2.%s" % i
self.tag_add(tag, start, end)
start = self.index(end)
tag = "header_even" if tag == "header_odd" else "header_odd"
except ValueError:
break
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
Autres conseils
modifier Je vois maintenant que vous êtes à la recherche d'une IUG. Je vais laisser cette mauvaise réponse pour la postérité.
import csv
def fixedwidth2csv(fw_name, csv_name, field_info, headings=None):
with open(fw_name, 'r') as fw_in:
with open(csv_name, 'rb') as csv_out: # 'rb' => 'r' for python 3
wtr = csv.writer(csv_out)
if headings:
wtr.writerow(headings)
for line in fw_in:
wtr.writerow(line[pos:pos+width].strip() for pos, width in field_info)