CSV richtig kodieren

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
slk
User
Beiträge: 4
Registriert: Dienstag 22. August 2017, 06:57

Hallihallo :)

Vielleicht finde ich ja hier die Antwort auf die Frage mit der ich mich nun schon ewig ärgere.

Ich habe über das arcpy.Modul *.xls und *.csv Tabellen einer *.dbf Tabelle erstellt, das Python Skript ist in UTF-8 kodiert. Die Umlaute passen im Excel Format wunderbar. Im CSV Dokument jedoch sehen diese immer furchtbar aus, anscheinend funktioniert die Kodierung hier nicht. Wenn ich manuell , außerhalb des Programmes , den Namen der Dokumente von *.xls auf *.csv ändere, stimmen die Umlaute jedoch.
Kann man die *.csv Dokumente evt noch einmal Kodieren oder gibt es hier eine Lösung für das Umlautproblem?

Mein zweites Problem ist, dass wenn ich das Skript im gleichen Ordner die Outputs generieren lasse, gibt es mir, obwohl ich

-----------* arcpy.env.overwriteOutput = True *----------------
für das Skript festgelegt haben nur bei den *.csv Dateien immer den Error:

arcgisscripting.ExecuteError: ERROR 000210: Ausgabe C:/Users/___/Desktop/091218_BLP/20170822\FNP.csv kann nicht erstellt werden.
Fehler beim Ausführen von (TableToTable).

Code: Alles auswählen


__author___ = ' '
__copyright__   = ' '
# coding = utf-8

import arcpy
import sys,os
import time
from datetime import date

reload(sys)
sys.setdefaultencoding('utf-8')
arcpy.env.overwriteOutput = True

folder = os.path.dirname(__file__)
arcpy.env.workspace = folder

for mxd_file in arcpy.ListFiles("*.mxd"):
    gdb_file = os.path.splitext(mxd_file)[0]+".gdb"
    print gdb_file

time = str(date.today()).replace("-","")

workspace = folder + "/" + gdb_file
print "Folder_________",workspace

arcpy.env.workspace = workspace

new_folder =  os.path.dirname(__file__) + "/" + time
if not os.path.exists(new_folder):
    os.makedirs(new_folder)

wanted_field = "Bearbeitung"

sql= str(wanted_field) + " > ' ' AND " + str(wanted_field) + " IS NOT NULL"

featureclass = arcpy.ListFeatureClasses()
print featureclass , "ist als FC in der .gdb enthalten"

for name in featureclass:
    for fc in arcpy.ListFeatureClasses(name):
        count = 0
        fc_fields = arcpy.ListFields(fc)
        for field in fc_fields:
           print field.name

            if field.name == wanted_field:
                print field.name , "_____________ist Spalte der .dbf Tabelle"

                Definition der Variablen
                fc_tableman = name + "_tableman"
                fc_select_tableview = name + "_select_tableman_xls"
                table_xls = new_folder + "/" + name + ".xls"
                table_csv = name + ".csv"

                arcpy.MakeTableView_management(fc, fc_tableman , sql)
                print fc_tableman

   
                with arcpy.da.SearchCursor (fc_tableman , wanted_field) as cursor:
                    for row in cursor:
                        count = count+1 
                print "Die Anzahl der Spalten in der Attributtabelle betraegt" , count , "."

                if count == 0:
                    print "Das Shapefile", fc ,"wird nicht neu erstellt, da es keine bearbeiteten Werte enthaelt."


                if count > 0:

                    arcpy.FeatureClassToFeatureClass_conversion(fc , new_folder , fc , sql)
                    print "Das Shapefile ", name , "mit den selektierten Attributen wurde erstellt."

                    arcpy.MakeTableView_management(new_folder + "/" +name + ".shp" , fc_select_tableview)
                    print fc_select_tableview , "wurde erstellt."

                    arcpy.TableToExcel_conversion(fc_select_tableview , table_xls)
                    print table_xls , "wurde erstellt."

                    arcpy.TableToTable_conversion(fc_select_tableview , new_folder , table_csv)
                    print table_csv , "wurde erstellt."
                    
Zuletzt geändert von Anonymous am Dienstag 22. August 2017, 08:45, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@slk: Wie der Python-Quelltext kodiert ist hat keinen Einfluss darauf wie irgendwelche anderen Daten kodiert werden. Und was heisst furchtbar aussehen? Wo? Welche Kodierung wird dort erwartet? So musst *Du* das halt auch kodieren. Oder einstellen das dort UTF-8 beim laden/dekodieren verwendet wird, wenn die Daten in UTF-8 kodiert sind.

Exceltabellen sind Unicode, da sieht natürlich alles prima aus. Und eine Exceltabelle so umzubenennen das die Dateinamensendung '.csv' ist, macht keinen Sinn, denn dadurch hast Du keine CSV-Datei sondern nur eine Exceltabelle mit einem falschen/irreführenden Namen.

Das gezeigte Programm hat einen Einrückungsfehler der nicht am Compiler vorbei kommt. Wenn man den behebt bekommt man einen Syntaxfehler weil da ein Kommentar ohne Kommentarzeichen drin steht (``#``).

Der Kodierungskommentar muss in der ersten oder zweiten Zeile stehen. Dort wo er jetzt steht, hat er keinen Effekt.

`sys.setdefaultencoding()` soll man nicht verwenden. Es ist extra Code vorhanden der diese Funktion nach der Initialisierung wieder entfernt, damit man das nicht macht. Deswegen muss man `reload()` verwenden um an die Funktion heran zu kommen. Wenn den Python-Entwicklern das nicht *wirklich* wichtig wäre, dann hätten sie die Funktion einfach nur als Implementierungsdetail gekennzeichnet, statt sie nach dem Start zu entfernen.

Die Schleife über die *.mxd-Dateinamen verrichtet zu viel Arbeit, denn letztendlich wird nur da Ergebnis des letzten Schleifendurchlaufs verwendet. An der Stelle könnte ein Programmfehler vorliegen, denn die Dokumentation von `ListFiles()` garantiert nichts über die Reihenfolge der Namen in der Liste. Den letzten Namne zu verwenden, bedeutet also letztendlich einen zufälligen Namen zu verwenden. Mag sein dass das zufällig immer der war der verwendet werden sollte, aber garantiert ist das halt nicht.

Zum zusammensetzen von Pfadteilen gibt es `os.path.join()`. Zeichenkettenoperationen sollte man dafür nicht verwenden, das kann Probleme geben.

Bei `time` würde sich die `format()`-Funktion eher anbieten als `str()` und dann `replace()` um die ungewollten Zeichen wieder los zu werden.

Die `format()`-Methode auf Zeichenketten macht die Definition von `sql` weniger kompliziert und leichter lesbar. Ist da wirklich ``> ' '``, also „grösser Zeichenkette mit einem Leerzeichen“ gemeint? Welche Werte können denn dort tatsächlich in den Daten vorkommen die kleiner sind, ausser der leeren Zeichenkette? Das ist etwas was ich kommentierungswürdig finde.

Die Initialisierung von `count` steht an einer falschen Stelle. Das gehört direkt dort hin wo es dann auch gebraucht wird. Das sieht so auch nach einem Programmfehler aus, denn das muss *jedes mal* ausgeführt werden wenn die Schleife zu zählen ausgeführt wird, sonst wird `count` ja immer weiter hochgezählt und es ist auch bei Suchen ohne Treffern nie mehr 0, was es ja sein müsste damit man eine Suche ohne Treffer erkennen kann.

Namen sollte man möglichst dort definieren wo sie verwendet werden und nicht zu weit davon entfernt. Man muss dann dort wo der Name verwendet wird, nicht suchen wie er definiert ist, und es ist dann auch einfacher den Code zu refaktorisieren, also beispielsweise Teile in eigene Funktionen heraus zu ziehen. Man muss dann den Bestandteile der neuen Funktion nicht über den ganzen Code verteilt zusammensuchen.

Das Zählen liesse sich auch mit `sum()` und einem Generatorausdruck in einer Zeile statt drei ausdrücken.

Für das Auswerten von `count` braucht man keine zwei ``if``\s, denn entweder ist `count` Null oder grösser als Null. Wenn man das eine geprüft hat, ist das andere einfach nur der ``else``-Fall dazu.

Ich lande dann als Zwischenergebnis ungefähr hier (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf-8
from __future__ import absolute_import, division, print_function
import os
from datetime import date

import arcpy


def main():
    # 
    # TODO Function does way too much.  Refactor.
    # 
    arcpy.env.overwriteOutput = True

    folder = os.path.dirname(__file__)
    arcpy.env.workspace = folder
    # 
    # TODO Maybe a bug to use the last file name without a guaranteed order.
    # 
    gdb_filename = os.path.splitext(arcpy.ListFiles('*.mxd')[-1])[0] + '.gdb'
    print(gdb_filename)

    workspace = os.path.join(folder, gdb_filename)
    print('Folder_________', workspace)
    arcpy.env.workspace = workspace

    time = format(date.today(), '%Y%m%d')
    new_folder = os.path.join(os.path.dirname(__file__), time)
    if not os.path.exists(new_folder):
        os.makedirs(new_folder)

    wanted_field = 'Bearbeitung'
    where_clause = "{0} > ' ' AND {0} IS NOT NULL".format(wanted_field)

    feature_classes = arcpy.ListFeatureClasses()
    print(feature_classes, 'sind als FCs in der .gdb enthalten')
    for name in feature_classes:
        for feature_class in arcpy.ListFeatureClasses(name):
            for field in arcpy.ListFields(feature_class):
                print(field.name)

                if field.name == wanted_field:
                    # 
                    # TODO Does it make sense to continue the loop
                    #   over the fields after the `wanted_field` was
                    #   found?  Could we even skip more iterations
                    #   from the outer loop(s) in this case?  Because
                    #   the code will overwrite views and probably
                    #   files if this branch is taken more than once
                    #   even for the most outer ``for`` loop!!!
                    # 
                    print(field.name, '___________ist Spalte der .dbf Tabelle')

                    view_name = name + '_tableman'
                    arcpy.MakeTableView_management(
                        feature_class, view_name, where_clause
                    )
                    print(view_name)

                    with arcpy.da.SearchCursor(view_name, wanted_field) as cursor:
                        count = sum(1 for _ in cursor)
                    print(
                        'Die Anzahl der Spalten in der Attributtabelle'
                        ' betraegt {0}.'.format(count)
                    )
                    if count:
                        arcpy.FeatureClassToFeatureClass_conversion(
                            feature_class,
                            new_folder,
                            feature_class,
                            where_clause,
                        )
                        print(
                            'Das Shapefile',
                            name,
                            'mit den selektierten Attributen wurde erstellt.',
                        )

                        view_name = name + '_select_tableman_xls'
                        arcpy.MakeTableView_management(
                            os.path.join(new_folder, name + '.shp'),
                            view_name,
                        )
                        print(view_name, 'wurde erstellt.')

                        xls_filename = os.path.join(new_folder, name + '.xls')
                        arcpy.TableToExcel_conversion(view_name, xls_filename)
                        print(xls_filename, 'wurde erstellt.')

                        csv_filename = name + '.csv'
                        arcpy.TableToTable_conversion(
                            view_name, new_folder, csv_filename
                        )
                        print(csv_filename, 'wurde erstellt.')
                    else:
                        print(
                            'Das Shapefile',
                            feature_class,
                            'wird nicht neu erstellt, da es keine bearbeiteten'
                            ' Werte enthaelt.',
                        )


if __name__ == '__main__':
    main()
Antworten